
安装拖拽插件
npm install vuedraggable
main.js 引入插件
// 图片拖动import vuedraggable from 'vuedraggable'// 全局组件挂载Vue.component('vuedraggable', vuedraggable)
如何使用
<imgUpload v-model="imgList" :limit="20" @input="handleProductImg" /><script>import imgUpload from '@/components/upload/imgUpload'export default {name: "imgTest",components: {imgUpload},data() {return {imgList:[],imgs:""};},methods: {handleProductImg(imgUrl) {this.imgList = imgUrl;// 逗号拼接this.imgs = imgUrl.join(",");},}}</script>
- 组件代码
imgUpload.vue,组件路径manage-ui/src/components/upload/imgUpload.vue
<template><div class="uploadWrapper"><vuedraggable:class="{ single: isSingle, maxHidden: isMaxHidden }"@end="onDragEnd"@start="onDragStart"class="vue-draggable"draggable=".draggable-item"tag="ul"v-model="imgList"><!-- 拖拽元素 --><li:key="item + index":style="{ width: width + 'px', height: height + 'px' }"class="draggable-item"v-for="(item, index) in imgList"><el-image :preview-src-list="imgList" :src="item"></el-image><div @click="onRemoveHandler(index)" class="shadow"><i class="el-icon-delete"></i></div></li><!-- 上传按钮 --><el-upload:action="url":before-upload="beforeUpload":headers="headers":limit="limit":multiple="!isSingle":on-exceed="onExceed":on-success="onSuccessUpload":show-file-list="false":style="{ width: width + 'px', height: height + 'px' }"accept=".jpg,.jpeg,.png,.gif"class="uploadBox"ref="uploadRef"slot="footer"><i class="el-icon-plus uploadIcon"><span class="uploading" v-show="isUploading">正在上传...</span><spanclass="limitTxt"v-if="!isUploading && limit && limit!==99 && !isSingle">最多{{ limit }}张</span></i></el-upload></vuedraggable></div></template><script>import vuedraggable from 'vuedraggable'// 获取token,用于后端接口登录校验,根据公司的业务自行移除或替换就行import {getToken} from "@/utils/auth"// import lrz from 'lrz' // 前端图片压缩插件import tools from '@/utils/tools'export default {name: 'ImgUpload',props: {// 图片数据(图片url组成的数组) 通过v-model传递value: {type: Array,default() {return []}},// 限制上传的图片数量limit: {type: Number,default: 8},// 限制上传图片的文件大小(kb)size: {type: Number,default: 500},// 是否是单图上传(单图上传就是已传图片和上传按钮重叠)isSingle: {type: Boolean,default: false},// 是否使用图片压缩useCompress: {type: Boolean,default: false},// 图片显示的宽度(px)width: {type: Number,default: 100},// 图片显示的高度(px)height: {type: Number,default: 100}},data() {return {url: process.env.VUE_APP_BASE_API + "/common/upload",headers: {Authorization: 'Bearer ' + getToken()},isUploading: false, // 正在上传状态isFirstMount: true // 控制防止重复回显}},computed: {// 图片数组数据imgList: {get() {return this.value},set(val) {if (val.length < this.imgList.length) {// 判断是删除图片时同步el-upload数据this.syncElUpload(val)}// 同步v-modelthis.$emit('input', val)}},// 控制达到最大限制时隐藏上传按钮isMaxHidden() {return this.imgList.length >= this.limit}},watch: {value: {handler(val) {if (this.isFirstMount && this.value.length > 0) {this.syncElUpload()}},deep: true}},mounted() {if (this.value.length > 0) {this.syncElUpload()}},methods: {// 同步el-upload数据syncElUpload(val) {const imgList = val || this.imgListthis.$refs.uploadRef.uploadFiles = imgList.map((v, i) => {return {name: 'pic' + i,url: v,status: 'success',uid: tools.createUniqueString()}})this.isFirstMount = false},// 上传图片之前beforeUpload(file) {this.isFirstMount = false// if (this.useCompress) {// // 图片压缩// return new Promise((resolve, reject) => {// lrz(file, { width: 1920 }).then((rst) => {// file = rst.file// }).always(() => {// if (validImgUpload(file, this.size)) {// this.isUploading = true// resolve()// } else {// reject(new Error())// }// })// })// } else {// if (validImgUpload(file, this.size)) {// this.isUploading = true// return true// } else {// return false// }// }},// 上传完单张图片onSuccessUpload(res, file, fileList) {// 这里需要根据你自己的接口返回数据格式和层级来自行修改if (res.url) {// 判断接口上传成功if (this.imgList.length < this.limit) {// 未超限时,把接口返回的图片url地址添加到imgListthis.imgList.push(res.url)this.$emit('input', this.imgList)}} else {// 判断接口上传失败this.syncElUpload()this.$message({type: 'error', message: res.msg})}this.isUploading = false},// 移除单张图片onRemoveHandler(index) {this.$confirm('确定删除该图片?', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).then(() => {this.imgList = this.imgList.filter((v, i) => {return i !== index})}).catch(() => {})},// 超限onExceed() {this.$refs.uploadRef.abort() // 取消剩余接口请求this.syncElUpload()this.$message({type: 'warning',message: `图片超限,最多可上传${this.limit}张图片`})},onDragStart(e) {e.target.classList.add('hideShadow')},onDragEnd(e) {e.target.classList.remove('hideShadow')}},components: {vuedraggable}}</script><style lang="less" scoped>/deep/ .el-upload {width: 100%;height: 100%;}// 上传按钮.uploadIcon {width: 100%;height: 100%;position: relative;display: flex;align-items: center;justify-content: center;border: 1px dashed #c0ccda;background-color: #fbfdff;border-radius: 6px;font-size: 20px;color: #999;.limitTxt,.uploading {position: absolute;bottom: 10%;left: 0;width: 100%;font-size: 14px;text-align: center;}}// 拖拽.vue-draggable {display: flex;flex-wrap: wrap;.draggable-item {margin-right: 5px;margin-bottom: 5px;border: 1px solid #ddd;border-radius: 6px;position: relative;overflow: hidden;.el-image {width: 100%;height: 100%;}.shadow {position: absolute;top: 0;right: 0;background-color: rgba(0, 0, 0, .5);opacity: 0;transition: opacity .3s;color: #fff;font-size: 20px;line-height: 20px;padding: 2px;cursor: pointer;}&:hover {.shadow {opacity: 1;}}}&.hideShadow {.shadow {display: none;}}&.single {overflow: hidden;position: relative;.draggable-item {position: absolute;left: 0;top: 0;z-index: 1;}}&.maxHidden {.uploadBox {display: none;}}}// el-image.el-image-viewer__wrapper {.el-image-viewer__mask {opacity: .8;}.el-icon-circle-close {color: #fff;}}</style>
参考
https://blog.csdn.net/u010059669/article/details/104038160
https://www.it610.com/article/1295907878112141312.htm
