<el-upload
v-model:file-list="fileList"
:accept="fileType.join(',')"
:action="updateUrl"
:before-upload="beforeUpload"
:class="['upload', drag ? 'no-border' : '']"
:drag="drag"
:headers="uploadHeaders"
:limit="limit"
:multiple="true"
:on-error="uploadError"
:on-exceed="handleExceed"
:on-success="uploadSuccess"
list-type="picture-card"
>
<div class="upload-empty">
<slot name="empty">
<Icon icon="ep:plus"/>
<!-- <span>请上传图片</span> -->
</slot>
</div>
<template #file="{ file }">
<!--这里是拖拽的关键代码,使用一个div包裹住需要拖拽的控件,在此div上进行设置拖拽事件-->
<div draggable="true" @dragstart="handleDragStart($event,file)" @drop="handleDrop($event,file)" @dragover.prevent>
<img :src="file.url" class="upload-image"/>
<div class="upload-handle" @click.stop>
<div class="handle-icon" @click="handlePictureCardPreview(file)">
<Icon icon="ep:zoom-in"/>
<span>查看</span>
</div>
<div class="handle-icon" @click="handleRemove(file)">
<Icon icon="ep:delete"/>
<span>删除</span>
</div>
</div>
</div>
</template>
</el-upload>
说明一下这段代码:这段代码的关键部分就是template中的div了,div上面也有注释,这里详细说一下,首先我们需要向div添加两个事件,
@dragstart="handleDragStart($event,file)"
@drop="handleDrop($event,file)"
这两个事件第一个是点击按下的时候执行,第二个事件是鼠标松开时执行。传入第一个必传参数$event,再传入第二个自选参数file,我这里因为是用的上传组件,所以只能拿到file,拿不到file在fileList中的index,也可能是我没见识,欢迎给我指教,拿到file以后也可以获取到在fileList中的index,倒是没啥影响,这里有一点很关键,就是这两个事件传入的file不是同一个,start传入的是点击时被拖拽的file,drop中的file是鼠标指针释放时所指的file,这也是el-upload组件提供给我们的一个比较方便的处理方案,否则我可能还需要更复杂的方法来获取释放位置。
如果大家使用v-for实现的组件列表拖拽功能,就可以直接传入index了,稍后我会把这两个方法的具体实现放出来,
我们先看在div中很重要的一项设置:
@dragover.prevent
缺了这一项配置,那么可能会导致鼠标释放时不触发,这项配置是为了阻止浏览器默认的拖拽行为,有助于确保 @drop 事件被正确触发。
// 拖拽排序相关的函数
const handleDragStart = (event, file) => {
// 输出被拖动的文件对象
console.log(file);
// 在当前fileList中查找被拖动文件的索引
const index = fileList.value.findIndex(element => element === file);
console.log(index);
// 将被拖动文件的索引设置到dataTransfer对象中,以便在拖放时使用
event.dataTransfer.setData('index', index.toString());
};
const handleDrop = (event, file) => {
// 在当前fileList中查找被释放文件的索引
const index = fileList.value.findIndex(element => element === file);
console.log(index);
// 阻止默认的拖放行为(例如打开链接等)
event.preventDefault();
// 从dataTransfer对象中获取被拖动项的索引
const draggedIndex = Number(event.dataTransfer.getData('index'));
// 从原始fileList中获取被拖动的项
const draggedItem = fileList.value[draggedIndex];
// 创建当前fileList的副本以进行修改
const updatedList = [...fileList.value];
// 从原始位置删除被拖动的项
updatedList.splice(draggedIndex, 1);
// 将被拖动的项插入到列表的新位置
updatedList.splice(index, 0, draggedItem);
// 使用修改后的列表更新fileList
fileList.value = updatedList;
// 发送一个事件通知父组件fileList已更新
emit('update:modelValue', updatedList);
};
这两个方法每一句的注释都很清晰了,所以不需要再多做说明了。最后附上运行效果吧