自定義input組件如何實(shí)現(xiàn)拖拽文件上傳
自定義input組件實(shí)現(xiàn)拖拽文件上傳
vue部分
<tag-input id="uploadTag" ref="uploadTag" v-model="fileNameList" size="small" @input="removeFile" ></tag-input>
邏輯部分
頁(yè)面加載時(shí)監(jiān)聽拖拽事件,監(jiān)聽后將文件放置下發(fā)fileList參數(shù)列表中
mounted() {
setTimeout(() => {
this.$nextTick(() => {
if (this.$refs.uploadTag) {
let dropEle = this.$refs.uploadTag.$el
// 禁止拖拽文件后打開文件
dropEle.addEventListener('drop', e => {
e.preventDefault();
e.stopPropagation();
}, false)
dropEle.addEventListener('dragover', e => {
e.preventDefault();
e.stopPropagation();
}, false)
dropEle.addEventListener('dragleave', e => {
e.preventDefault();
e.stopPropagation();
}, false)
// 處理拖拽文件的邏輯
dropEle.addEventListener('drop', e => this.watchFileUpload(e))
}
})
}, 1000)
} // 拖拽上傳
private watchFileUpload(e) {
e.preventDefault();
e.stopPropagation();
var df = e.dataTransfer;
var dropFiles = []; // 拖拽的文件,會(huì)放到這里
var dealFileCnt = 0; // 讀取文件是個(gè)異步的過(guò)程,需要記錄處理了多少個(gè)文件了
var allFileLen = df.files.length; // 所有的文件的數(shù)量,給非Chrome瀏覽器使用的變量
// 檢測(cè)是否已經(jīng)把所有的文件都遍歷過(guò)了
function checkDropFinish() {
dealFileCnt++;
}
if (df.items !== undefined) {
// Chrome拖拽文件邏輯
for (var i = 0; i < df.items.length; i++) {
var item = df.items[i];
if (item.kind === "file" && item.webkitGetAsEntry().isFile) {
var file = item.getAsFile();
dropFiles.push(file);
}
}
} else {
// 非Chrome拖拽文件邏輯
for (var i = 0; i < allFileLen; i++) {
var dropFile = df.files[i];
if (dropFile.type) {
dropFiles.push(dropFile);
checkDropFinish();
} else {
try {
var fileReader = new FileReader();
fileReader.readAsDataURL(dropFile.slice(0, 3));
fileReader.addEventListener('load', function (e) {
console.log(e, 'load');
dropFiles.push(dropFile);
checkDropFinish();
}, false);
fileReader.addEventListener('error', function (e) {
console.log(e, 'error,不可以上傳文件夾');
checkDropFinish();
}, false);
} catch (e) {
console.log(e, 'catch error,不可以上傳文件夾');
checkDropFinish();
}
}
}
}
dropFiles.forEach(item => {
this.fileList.push(item)
})
this.fileNameList = this.fileList.map(item => {
if (item.name) {
return item.name
}
if (item.fileName) {
return item.fileName
}
});
}刪除當(dāng)前文件
// 附件刪除 下拉框
private removeFile(nameList, name) {
// 記錄刪除的附件信息
this.fileList.splice(this.fileList.findIndex(item => item.fileName === name || item.name === name), 1)
this.fileNameList = this.fileList.map(item => item.name || item.fileName);
}封裝的tag-input組件
<template>
<div
class="yh-input-tag input-tag-wrapper"
ref="InputTag"
@click="foucusTagInput"
>
<el-tag
v-for="(tag, idx) in innerTags"
:key="tag"
:size="size"
:closable="!readonly"
:disable-transitions="false"
@close="remove(tag, idx)"
>{{ tag }}</el-tag
>
<input
:readonly="readonly || readonlyIpt"
class="tag-input"
:class="[size ? 'yh-input-tag--' + size : '']"
:style="widthStyle"
:placeholder="isplaceholder"
v-model="newTag"
@keydown.delete.stop="removeLastTag"
@keydown="addNew"
@blur="blurTagInput"
/>
</div>
</template>
<script>
export default {
name: 'InputTag',
props: {
value: {
type: Array,
default: () => []
},
addTagOnKeys: {
type: Array,
default: () => [13, 188, 9]
},
readonly: {
type: Boolean,
default: false
},
// 輸入框只讀
readonlyIpt: {
type: Boolean,
default: false
},
size: String,
placeholder: {
type: String,
default: '請(qǐng)輸入'
}
},
inject: {
elForm: {
default: ''
},
elFormItem: {
default: ''
}
},
data () {
return {
newTag: '',
innerTags: [...this.value],
currentTag: null,
widthStyle: {
minWidth: '10px'
}
}
},
computed: {
isplaceholder () {
let str = ''
if(this.value?.length > 0) {
this.$nextTick(() => {
if (this.$refs.yhInputTag) {
this.$refs.InputTag.style.padding = '0'
}
})
str = ''
} else {
this.$nextTick(() => {
if (this.$refs.yhInputTag) {
this.$refs.InputTag.style.padding = '0 15px'
}
})
str = this.placeholder
}
return str
},
// 表單禁用關(guān)聯(lián)
inputDisabled() {
return this.disabled || (this.elForm || {}).disabled;
}
},
watch: {
value: {
handler(newVal, oldVal) {
if (this.elForm && oldVal !== undefined && newVal !== oldVal) {
this.elForm.validateField(this.elFormItem.prop)
}
if (newVal) {
this.innerTags = [...newVal]
}
},
deep: true,
immediate: true
}
},
methods: {
foucusTagInput () {
if (this.readonly || this.readonlyIpt || !this.$el.querySelector('.tag-input')) {
return
} else {
this.$el.querySelector('.tag-input').focus()
this.widthStyle = {
minWidth: '10px'
}
}
},
blurTagInput (e) {
this.addNew(e)
this.widthStyle = {
width: '0px'
}
},
addNew (e) {
if (e && (!this.addTagOnKeys.includes(e.keyCode)) && (e.type !== 'blur')) {
return
}
if (e) {
e.stopPropagation()
e.preventDefault()
}
let addSuucess = false
if (this.newTag.includes(',')) {
this.newTag.split(',').forEach(item => {
if (this.addTag(item.trim())) {
addSuucess = true
}
})
} else {
if (this.addTag(this.newTag.trim())) {
addSuucess = true
}
}
if (addSuucess) {
this.tagChange()
this.newTag = ''
}
},
addTag (tag) {
tag = tag.trim()
if (tag && !this.innerTags.includes(tag)) {
this.innerTags.push(tag)
return true
}
return false
},
remove (tag, index) {
this.innerTags.splice(index, 1)
this.currentTag = tag
this.tagChange()
},
removeLastTag () {
if (this.newTag) {
return
}
this.innerTags.pop()
this.tagChange()
},
tagChange () {
this.$forceUpdate()
this.$emit('input', JSON.parse(JSON.stringify(this.innerTags)), this.currentTag)
}
}
}
</script>
<style scoped>
.input-tag-wrapper {
position: relative;
font-size: 14px;
background-color: #fff;
background-image: none;
border-radius: 4px;
border: 1px solid #DCDFE6;
box-sizing: border-box;
color: #575757;
display: inline-block;
cursor: text;
outline: none;
padding: 0 15px;
transition: border-color .2s cubic-bezier(.645,.045,.355,1);
width: 100%;
line-height: normal;
&:hover{
border-color: #C5C6C7;
}
&:focus{
border-color: #d32f2f;
}
.el-tag{
box-sizing: border-box;
border-color: transparent;
margin: 2px 0 2px 6px;
background-color: #f0f2f5;
display: inline-flex;
max-width: 100%;
align-items: center;
}
}
.tag-input {
background: transparent;
border: 0;
font-size: 14px;
outline: none;
padding-left: 0;
height: 26px;
&::placeholder {
color: #C8C9CA;
}
}
.yh-input-tag--mini{
height: 26px;
line-height: 26px;
.tag {
height: 16px;
}
}
.yh-input-tag--small{
height: 30px;
line-height: 30px;
.tag {
height: 20px;
}
}
.yh-input-tag--medium{
height: 34px;
line-height: 34px;
.tag {
height: 24px;
}
}
// 表單標(biāo)簽選擇器必填樣式
.el-form-item.is-error .input-tag-wrapper,
.el-form-item.is-error .input-tag-wrapper:focus {
border-color: #bc1126 !important;
}
</style>最后實(shí)現(xiàn)的效果
![]()
可支持手動(dòng)拖拽上傳
多圖上傳組件vue
小編參加的第一個(gè)項(xiàng)目,就遇到了麻煩的多圖上傳,通過(guò)多天的努力,寫出了一個(gè)多圖的組件,希望可以幫助到大家
組件template部分
多圖上傳按鈕+多圖上傳彈窗+圖片上的預(yù)覽刪除圖標(biāo)
<template>
<div>
<div class="many">
<el-form-item>
<div class="upload-item">
<el-button type="primary" @click="uploadFile">多圖上傳</el-button>
</div>
</el-form-item>
</div>
<el-dialog title="圖片預(yù)覽" :visible.sync="dialogImgVisible" width="50%">
<img :src="dialogImageUrl" alt="" class="previewImg" />
</el-dialog>
<!--多圖上傳彈窗界面-->
<el-dialog :title="'上傳'" :visible.sync="dialogFormVisible" custom-class="pub_dialog" >
<el-form style="width: 750px;height: 380px">
<!--內(nèi)容部分 -->
<el-form-item><!---->
<div style="display: flex;justify-content: center">
<label>選擇文件:</label>
<div>
<div class="desc">支持 jpg, png 圖片格式,且不超過(guò)500kb</div>
<el-upload
:action="UPLOAD_URL"
:headers="authorToken"
:auto-upload="true"
accept="image/jpg,image/png,image/jpeg"
:on-success="handleSuccess"
:before-upload="handleBeforeUpload"
:show-file-list="false"
multiple
:limit="10"
:on-exceed="handleExceed"
:file-list="fileList">
<el-button size="small" type="primary">上傳圖片</el-button>
</el-upload>
</div>
</div>
<div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
<div class="item" v-for="(item,index) in images" :key="index">
<img :src="item.url" alt="" :key="index" style=" width: 45%;height: 100%" class = "imgList">
<div class="scissor-icon">
<i class="el-icon-scissors" @click="changeFile(item)"></i>
</div>
<div class="delete-icon">
<i class="el-icon-delete" @click="handleRemove(item)"></i>
</div>
<div class="search-icon">
<i class="el-icon-search" @click="handlePreview(item)"></i>
</div>
<el-input
type="textarea"
:autosize="{ minRows: 7, maxRows: 7}"
placeholder="請(qǐng)輸入圖片描述"
v-model="item.manyDescription"
:key="index"
style=" width: 55%;height: 100%;margin-left: 10px">
</el-input>
</div>
</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="closeDialog">確 定</el-button>
</div>
</el-dialog>
</div>
</template>
組件script部分
1.變量數(shù)據(jù)區(qū)域
代碼如下(示例):
<script>
export default {
name: "UploadMany",
data() {
return {
textarea:'',
dialogImageUrl: '',
dialogImgVisible: false,
dialogVisible: false,
fileList: [],
imgs: [],
images: [],
UPLOAD_URL: "/v1/admin/common/upload",//這里填寫你的后端上傳接口地址
authorToken: {
Authorization: 'Bearer ' + sessionStorage.getItem("token"),
siteId:sessionStorage.getItem("siteId")
},
param: {
token: ''
},
fileNum: 0,
num: 0,
dialogFormVisible: false,//添加表單彈出框是否顯示
dialogChangeVisible: false,
picsList: [], //頁(yè)面顯示的數(shù)組
// 防止重復(fù)提交
loading: true,
}
},
2.方法區(qū)域
代碼如下(示例):
methods: {
//刪除方法
handleRemove(file) {
console.log(file)
// 1.獲取將要?jiǎng)h除的圖片的臨時(shí)路徑
const filePath = file.url
// 2.從數(shù)組中,找到這個(gè)圖片對(duì)應(yīng)的索引值
const i = this.imgs.findIndex((x) => x.url === filePath)
// 3.調(diào)用數(shù)組的 splice 方法,把圖片信息對(duì)象,從 pics 數(shù)組中移除
this.imgs.splice(i, 1)
console.log(this.imgs)
},
//預(yù)覽方法
handlePreview(file) {
console.log(file);
this.dialogImageUrl = file.url;
this.dialogImgVisible = true;
},
//限制上傳文件個(gè)數(shù)
handleExceed(files, fileList) {
this.$message.warning(`當(dāng)前限制選擇 10 個(gè)文件,本次選擇了 ${files.length} 個(gè)文件,共選擇了 ${files.length + fileList.length} 個(gè)文件`);
},
//上傳成功后
handleSuccess(response, fileList) {
console.log(response);
console.log(fileList)
this.loading = false
if(response.code === 200){
this.imgs.push({name: response.data.resourceName, url: response.data.resourceUrl, manyDescription: '', manyResourceId: response.data.id})
this.num++;
if(this.num == this.fileNum){
for(let i = 0; i < this.num ; i++){
this.$emit('getManyImg', this.imgs[i])
}
this.num = 0;
this.fileNum = 0;
this.images = this.imgs;
this.imgs = [];
}
}else{
this.$message.error('上傳失敗');
}
},
handleBeforeUpload(file) {
// 這里做可以做文件校驗(yàn)操作
const isImg = /^image\/\w+$/i.test(file.type)
if (!isImg && this.fileType == 'image/*') {
this.$message.error('只能上傳 JPG、PNG、GIF 格式!')
return false
}
this.fileNum++;
},
uploadFile(){
this.dialogFormVisible = true;
this.loading = false;
},
closeDialog(){
this.dialogFormVisible = false;
this.imgs = [];
this.images = [];
}
}
}
組件使用
1.在你需要用到的界面vue里導(dǎo)入組件
import UploadMany from '@/components/upload/UploadMany';
import {getToken} from '@/utils/auth';
export default {
name: "TestEditor",
components: {
UploadMany,
},
2.template部分使用組件
<el-col :span="24">
<el-form-item prop="manyImg" label="多圖上傳:" :label-width="imgWidth" class="form">
<upload-many v-model="dialogForm.manyImg" @getManyImg="getManyImg" ></upload-many>
<div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
<div class="item" v-for="(itemPhoto,indexPhoto) in dialogForm.images" :key="indexPhoto">
<div class="item-left" style="position: relative">
<img :src="itemPhoto.url" alt="" :key="indexPhoto" class = "imgList">
<div class="item-bottom">
<div class="search-icon">
<i class="el-icon-search" @click="handlePreview(itemPhoto)"></i>
</div>
<div class="delete-icon">
<i class="el-icon-delete" @click="handleRemove(itemPhoto)"></i>
</div>
</div>
</div>
<el-input
type="textarea"
:autosize="{ minRows: 7, maxRows: 7}"
placeholder="請(qǐng)輸入圖片描述"
v-model="itemPhoto.manyDescription"
style=" width: 55%;height: 100%;margin-left: 10px">
</el-input>
</div>
</div>
</el-form-item>
</el-col>
3.方法部分
getManyImg(imgs) {
this.dialogForm.images.push(imgs);
console.log(this.dialogForm.images)
},
handleRemove(file) {
console.log(file)
// 1.獲取將要?jiǎng)h除的圖片的臨時(shí)路徑
const filePath = file.url
// 2.從數(shù)組中,找到這個(gè)圖片對(duì)應(yīng)的索引值
const i = this.dialogForm.images.findIndex((x) => x.url === filePath)
// 3.調(diào)用數(shù)組的 splice 方法,把圖片信息對(duì)象,從 pics 數(shù)組中移除
this.dialogForm.images.splice(i, 1)
},
//預(yù)覽圖片
handlePreview(file) {
console.log(file);
this.dialogImageUrl = file.url;
this.dialogImgVisible = true;
},
組件完整代碼(含裁剪組件,不需要請(qǐng)手動(dòng)刪除)
<template>
<div>
<div class="many">
<el-form-item>
<div class="upload-item">
<el-button type="primary" @click="uploadFile">多圖上傳</el-button>
</div>
</el-form-item>
</div>
<!--裁剪彈窗-->
<!-- vueCropper 剪裁圖片實(shí)現(xiàn)-->
<el-dialog title="圖片剪裁" :visible.sync="dialogChangeVisible" append-to-body>
<div class="cropper-content">
<div class="cropper" style="text-align:center">
<vueCropper
ref="cropper"
:img="option.img"
:outputSize="option.size"
:outputType="option.outputType"
:info="true"
:full="option.full"
:canMove="option.canMove"
:canMoveBox="option.canMoveBox"
:original="option.original"
:autoCrop="option.autoCrop"
:fixed="option.fixed"
:fixedNumber="option.fixedNumber"
:centerBox="option.centerBox"
:infoTrue="option.infoTrue"
:fixedBox="option.fixedBox"
></vueCropper>
</div>
</div>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogChangeVisible = false">取 消</el-button>
<el-button type="primary" @click="finish" :loading="loading">確認(rèn)</el-button>
</div>
</el-dialog>
<el-dialog title="圖片預(yù)覽" :visible.sync="dialogImgVisible" width="50%">
<img :src="dialogImageUrl" alt="" class="previewImg" />
</el-dialog>
<!--多圖上傳彈窗界面-->
<el-dialog :title="'上傳'" :visible.sync="dialogFormVisible" custom-class="pub_dialog" >
<el-form style="width: 750px;height: 380px">
<!--內(nèi)容部分 -->
<el-form-item><!---->
<div style="display: flex;justify-content: center">
<label>選擇文件:</label>
<div>
<div class="desc">支持 jpg, png 圖片格式,且不超過(guò)500kb</div>
<el-upload
:action="UPLOAD_URL"
:headers="authorToken"
:auto-upload="true"
accept="image/jpg,image/png,image/jpeg"
:on-success="handleSuccess"
:before-upload="handleBeforeUpload"
:show-file-list="false"
multiple
:limit="10"
:on-exceed="handleExceed"
:file-list="fileList">
<el-button size="small" type="primary">上傳圖片</el-button>
</el-upload>
</div>
</div>
<div class="fileList" style="margin-top: 10px;display: flex;flex-wrap: wrap;">
<div class="item" v-for="(item,index) in images" :key="index">
<img :src="item.url" alt="" :key="index" style=" width: 45%;height: 100%" class = "imgList">
<div class="scissor-icon">
<i class="el-icon-scissors" @click="changeFile(item)"></i>
</div>
<!-- <div class="refresh-icon">-->
<!-- <i class="el-icon-refresh" @click="handleRemove()"></i>-->
<!-- </div>-->
<div class="delete-icon">
<i class="el-icon-delete" @click="handleRemove(item)"></i>
</div>
<div class="search-icon">
<i class="el-icon-search" @click="handlePreview(item)"></i>
</div>
<el-input
type="textarea"
:autosize="{ minRows: 7, maxRows: 7}"
placeholder="請(qǐng)輸入圖片描述"
v-model="item.manyDescription"
:key="index"
style=" width: 55%;height: 100%;margin-left: 10px">
</el-input>
</div>
</div>
</el-form-item>
</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="dialogFormVisible = false">取 消</el-button>
<el-button type="primary" @click="closeDialog">確 定</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import VueCropper from 'vue-cropper'
import Vue from "vue";
Vue.use(VueCropper)
export default {
name: "UploadMany",
data() {
return {
textarea:'',
dialogImageUrl: '',
dialogImgVisible: false,
dialogVisible: false,
fileList: [],
imgs: [],
images: [],
UPLOAD_URL: "/v1/admin/common/upload",
authorToken: {
Authorization: 'Bearer ' + sessionStorage.getItem("token"),
siteId:sessionStorage.getItem("siteId")
},
param: {
token: ''
},
fileNum: 0,
num: 0,
dialogFormVisible: false,//添加表單彈出框是否顯示
dialogChangeVisible: false,
// 裁剪組件的基礎(chǔ)配置option
option: {
img: '', // 裁剪圖片的地址
info: true, // 裁剪框的大小信息
outputSize: 0.8, // 裁剪生成圖片的質(zhì)量
outputType: 'jpeg', // 裁剪生成圖片的格式
canScale: false, // 圖片是否允許滾輪縮放
autoCrop: true, // 是否默認(rèn)生成截圖框
// autoCropWidth: 300, // 默認(rèn)生成截圖框?qū)挾?
// autoCropHeight: 200, // 默認(rèn)生成截圖框高度
fixedBox: true, // 固定截圖框大小 不允許改變
fixed: true, // 是否開啟截圖框?qū)捀吖潭ū壤?
fixedNumber: [7, 5], // 截圖框的寬高比例
full: true, // 是否輸出原圖比例的截圖
canMoveBox: false, // 截圖框能否拖動(dòng)
original: false, // 上傳圖片按照原始比例渲染
centerBox: false, // 截圖框是否被限制在圖片里面
infoTrue: true // true 為展示真實(shí)輸出圖片寬高 false 展示看到的截圖框?qū)捀?
},
picsList: [], //頁(yè)面顯示的數(shù)組
// 防止重復(fù)提交
loading: true,
}
},
methods: {
handleRemove(file) {
console.log(file)
// 1.獲取將要?jiǎng)h除的圖片的臨時(shí)路徑
const filePath = file.url
// 2.從數(shù)組中,找到這個(gè)圖片對(duì)應(yīng)的索引值
const i = this.imgs.findIndex((x) => x.url === filePath)
// 3.調(diào)用數(shù)組的 splice 方法,把圖片信息對(duì)象,從 pics 數(shù)組中移除
this.imgs.splice(i, 1)
console.log(this.imgs)
},
handlePreview(file) {
console.log(file);
this.dialogImageUrl = file.url;
this.dialogImgVisible = true;
},
handleExceed(files, fileList) {
this.$message.warning(`當(dāng)前限制選擇 10 個(gè)文件,本次選擇了 ${files.length} 個(gè)文件,共選擇了 ${files.length + fileList.length} 個(gè)文件`);
},
handleSuccess(response, fileList) {
console.log(response);
console.log(fileList)
this.loading = false
if(response.code === 200){
this.imgs.push({name: response.data.resourceName, url: response.data.resourceUrl, manyDescription: '', manyResourceId: response.data.id})
this.num++;
if(this.num == this.fileNum){
for(let i = 0; i < this.num ; i++){
this.$emit('getManyImg', this.imgs[i])
}
this.num = 0;
this.fileNum = 0;
this.images = this.imgs;
this.imgs = [];
}
}else{
this.$message.error('上傳失敗');
}
},
// 裁剪按鈕 限制圖片大小
changeFile(file) {
console.log(file)
this.option.img = file.url
console.log(this.option.img)
this.dialogChangeVisible = true
},
// 點(diǎn)擊裁剪
finish() {
this.$refs.cropper.getCropBlob((data) => {
console.log(data)
console.log(data.size)
this.$data.dialogChangeVisible = false
this.axios.post("/v1/admin/common/upload",data).then((res) => {
let code = res.data.code;
if (code == 200) {
this.$data.dialogFormVisible = false
this.$message.success("上傳成功");
}
}).catch((error) => {
console.log(error);
});
})
},
handleBeforeUpload(file) {
// 這里做可以做文件校驗(yàn)操作
const isImg = /^image\/\w+$/i.test(file.type)
if (!isImg && this.fileType == 'image/*') {
this.$message.error('只能上傳 JPG、PNG、GIF 格式!')
return false
}
this.fileNum++;
},
uploadFile(){
this.dialogFormVisible = true;
this.loading = false;
},
closeDialog(){
this.dialogFormVisible = false;
this.imgs = [];
this.images = [];
}
}
}
</script>
<style lang="scss" scoped>
.el-dialog{
width: 50%;
}
.item {
width: 300px;
height: 140px;
position: relative;
display: flex;
margin: 10px;
.delete-icon {
display: none;
}
.refresh-icon {
display: none;
}
.search-icon {
display: none;
}
.scissor-icon {
display: none;
}
&:hover {
.scissor-icon {
display: block;
position: absolute;
width: 35px;
height: 40px;
line-height: 40px;
left: 100px;
top: 100px;
background: rgba(59, 60, 61, 0.5);
// box-sizing: content-box;
z-index: 999;
cursor: pointer;
text-align: center;
i {
margin: 8px 10px 0 0;
display: block;
font-size: 24px;
color: white;
}
}
.delete-icon {
display: block;
position: absolute;
width: 35px;
height: 40px;
left: 0px;
top: 100px;
background: rgba(59, 60, 61, 0.5);
// box-sizing: content-box;
z-index: 999;
cursor: pointer;
text-align: center;
i {
margin: 8px 10px 0 10px;
display: block;
font-size: 24px;
color: white;
}
}
.refresh-icon {
display: block;
position: absolute;
width: 35px;
height: 40px;
left: 35px;
top: 100px;
background: rgba(59, 60, 61, 0.5);
// box-sizing: content-box;
z-index: 999;
cursor: pointer;
text-align: center;
i {
margin: 8px 10px 0 0;
display: block;
font-size: 24px;
color: white;
}
}
.search-icon {
display: block;
position: absolute;
width: 65px;
height: 40px;
left: 35px;
top: 100px;
background: rgba(59, 60, 61, 0.5);
// box-sizing: content-box;
z-index: 999;
cursor: pointer;
text-align: center;
i {
margin: 8px 10px 0 10px;
display: block;
font-size: 24px;
color: white;
}
}
}
}
.imgList {
border: 1px dashed #d9d9d9;
border-radius: 5px;
box-sizing: border-box;
width: 180px;
height: 180px;
margin-top: 0px;
&:hover {
border: 1px dashed #409eff;
}
}
// 截圖
.cropper-content {
.cropper {
width: auto;
height: 300px;
}
}
.previewImg {
width: 50%;
height: 100%
}
</style>
效果展示

總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue + typescript + 極驗(yàn)登錄驗(yàn)證的實(shí)現(xiàn)方法
這篇文章主要介紹了vue + typescript + 極驗(yàn) 登錄驗(yàn)證的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-06-06
vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例
本文主要介紹了vue+d3js+fastapi實(shí)現(xiàn)天氣柱狀圖折線圖餅圖的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2025-04-04
vue視頻播放插件vue-video-player的具體使用方法
這篇文章主要介紹了vue視頻播放插件vue-video-player的具體使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
解決vue中使用Axios調(diào)用接口時(shí)出現(xiàn)的ie數(shù)據(jù)處理問(wèn)題
今天小編就為大家分享一篇解決vue中使用Axios調(diào)用接口時(shí)出現(xiàn)的ie數(shù)據(jù)處理問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
聊聊vue集成sweetalert2提示組件的問(wèn)題
這篇文章主要介紹了vue 集成 sweetalert2 提示組件的問(wèn)題,本文通過(guò)項(xiàng)目案例實(shí)例代碼相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2021-11-11
Vite打包性能優(yōu)化之開啟Gzip壓縮實(shí)踐過(guò)程
vue前端項(xiàng)目發(fā)布的時(shí)候,打包可實(shí)現(xiàn)gzip格式的壓縮,下面這篇文章主要給大家介紹了關(guān)于Vite打包性能優(yōu)化之開啟Gzip壓縮的相關(guān)資料,需要的朋友可以參考下2022-12-12
vue 根據(jù)數(shù)組中某一項(xiàng)的值進(jìn)行排序的方法
這篇文章主要介紹了vue 根據(jù)數(shù)組中某一項(xiàng)的值進(jìn)行排序的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08

