el-upload 上传多张图片保证顺序 并支持拖拽
<template>
<div class="goods-upload_img_comp">
<el-upload
action="#"
list-type="picture-card"
:before-upload="beforeUpload"
:limit="imgListLength"
:http-request="KKHttpRequestImg"
:file-list="imgList"
drag
accept=".png,.jpg,.jpeg"
ref="uploadRef"
:multiple="true"
:class="[isShowUpload]"
class="goods-upload_img-common"
>
<i class="goods-icon-plus"></i>
<div slot="file" slot-scope="{ file }">
<img
class="goods-upload-list__item-thumbnail"
style="width: 100px; height: 100px; cursor: pointer"
:src="file.url"
alt=""
@click="handlePictureCardPreview(file)"
/>
<img
class="goods-upload-list-delete"
src="@/assets/delete.png"
alt=""
@click.stop="clickDel(file)"
/>
</div>
</el-upload>
<p class="goods-tip">
单个图片大小不超过2M,支持png、jpg、jpeg,拖拽可调整顺序,快捷编辑的图片将优先在富文本框的内容上方展示
</p>
<el-image-viewer
v-if="dialogVisible"
class="image_viewer"
:on-close="
() => {
dialogVisible = false
}
"
:url-list="[dialogImageUrl]"
/>
</div>
</template>
<script>
import { getDate, newMathNumber } from '@/utils/upload'
import ElImageViewer from 'element-ui/packages/image/src/image-viewer'
import { dragImg } from './dragTable.js'
import { deepClone } from '@/utils/index.js'
export default {
name: 'UploadImg',
props: {
// 限制图片大小 单位M
imgSize: {
type: Number,
default: 2
},
// 限制图片数量
imgListLength: {
type: Number,
default: 1
},
value: {
default: '',
type: []
}
},
components: { ElImageViewer },
data() {
return {
dialogImageUrl: '',
disabled: false,
dialogVisible: false,
imgList: [],
uploadQueue: [],
isUpload: false
}
},
watch: {
value: {
handler(nv) {
this.imgList = deepClone(nv)
},
immediate: true
}
},
computed: {
isShowUpload() {
if (this.imgList?.length >= this.imgListLength) {
return 'goods-hiddenUpload'
}
return ''
}
},
mounted() {
this.$nextTick(() => {
dragImg(this)
})
},
methods: {
// [AI-自定义上传方法操作]
async promiseFun(params) {
try {
await this.$store.dispatch('ossclient/getStsToken')
const file = params.file
this.showFileName = file.name
const dates = getDate()
const mathNum = newMathNumber(4)
// 生成文件名
const stroeAs =
'tempfile/template/pc/' +
+dates +
'/' +
new Date().getTime() +
'_' +
mathNum +
file.name.substring(file.name.lastIndexOf('.'))
const result = await this.$store.getters.client.put(stroeAs, file)
const imgProduct = {
url: result.url,
uid: file.uid
}
// 上传完成后重新初始化拖拽
this.$message.success('上传成功')
return imgProduct
} catch (error) {
console.log('???error', error)
}
},
// [AI-队列上传]
async processUploadQueue() {
if (this.isUploading) return
this.isUploading = true
try {
while (this.uploadQueue.length > 0) {
const item = this.uploadQueue.shift() // 从队列头部取出并移除
try {
const res = await this.promiseFun(item)
this.imgList.push(res)
// 批量更新以减少触发次数
this.$emit('input', [...this.imgList])
} catch (error) {
console.error('上传失败项:', item.file.name, error)
// 可选:将失败项重新加入队列或进行其他处理
}
}
} finally {
this.isUploading = false
// 检查是否有新项在处理过程中加入
if (this.uploadQueue.length > 0) {
this.processUploadQueue()
}
}
},
// [AI-添加任务到队列]
async KKHttpRequestImg(params) {
this.uploadQueue.push(params)
this.$nextTick(() => this.processUploadQueue())
},
clickDel(file) {
this.handleRemove(file)
this.$message.success('已删除')
},
handleRemove(file) {
this.imgList = this.imgList.filter(e => e.url !== file.url)
this.$emit('input', this.imgList)
},
handlePictureCardPreview(file) {
this.dialogImageUrl = file.url
this.dialogVisible = true
},
beforeUpload(file) {
const isJPG =
file.type === 'image/jpeg' ||
file.type === 'image/png' ||
file.type === 'image/jpg'
const isLt2M = file.size / 1024 / 1024 < this.imgSize
console.log('ceshi')
if (!isJPG) {
this.$message.error('上传图片只能是jpeg/jpg/png 格式!')
return false
} else if (!isLt2M) {
this.$message.error(`上传图片大小不能超过 ${this.imgSize}MB!`)
return false
} else {
return true
}
}
}
}
</script>
<style scoped lang="scss">
.goods-upload_img_comp {
padding: 0px 16px 16px 16px;
::v-deep {
.goods-upload--picture-card,
.goods-upload-dragger,
.goods-upload-list__item {
height: 100px;
width: 100px;
display: inline-block;
line-height: 100px;
margin-bottom: 0px;
}
// .goods-list-enter-to {
// display: none;
// }
.goods-hiddenUpload .goods-upload--picture-card {
display: none;
}
.upload_msg {
margin: 0;
font-size: 14px;
line-height: 14px;
color: #999999;
}
.goods-upload-list__item.is-ready {
display: none;
}
.goods-upload-list__item-status-label {
display: none;
}
.goods-upload-list--picture-card {
display: inline-block;
}
}
}
.goods-tip {
font-weight: 400;
font-size: 12px;
color: #999;
text-align: left;
line-height: 20px;
margin-top: 16px;
}
.goods-upload-list-delete {
width: 16px;
height: 16px;
position: absolute;
top: 2px;
right: 2px;
z-index: 9;
cursor: pointer;
}
</style>
dragTable.js文件
import Sortable from 'sortablejs'
export const dragImg = _this => {
const dragElWrap =
_this.$refs['uploadRef'].$el.querySelector('.goods-upload-list')
console.log('dragElWrap', dragElWrap)
Sortable.create(dragElWrap, {
animation: 150,
onEnd({ newIndex, oldIndex }) {
_this.imgList.splice(newIndex, 0, _this.imgList.splice(oldIndex, 1)[0])
_this.$emit('input', _this.imgList)
// _this.imgList.forEach((item, index) => {
// item.sort = index
// })
}
})
}