elementPlus 上传组件支持拖拽排序

演示地址:

请点这里(部署在github,没有科学上网会比较慢)
需要登录直接点击登录即可,账号密码默认已填写好

项目源码地址:

请点这里

说明

因为公司项目需要,编辑商品信息的时候对商品主图的顺序要求比较高,而elementPlus自带的上传组件不支持该功能,所以需要进行一波改造。通过其他相关文章,了解到
SortableJS / Vue.Draggable
这个vue组件比较不错,支持vue3和vue2

核心思路

因为elementPlus不支持拖拽排序,所以我们只利用elementPlus的upload组件的上传功能,禁用他的 list-type(照片墙) 配置,改用Vue.Draggable这个组件去渲染图片列表。核心是维护一个公共已上传的文件列表集合,每次上传成功后往列表中放入一个元素。利用双向绑定使得Vue.Draggable组件中可以实时显示出刚上传成功的文件,同时预览和删除功能也在Vue.Draggable组件中实现

代码

首先需要安装Vue.Draggable

yarn add vuedraggable

npm i -S vuedraggable

vue组件代码如下:

<template>
	<div class="layout-padding">
		<el-row>
			<el-col :span="24" style="border:1px solid #E4E7ED;">
				<draggable v-model="state.fileList" item-key="id">
					<template #item="{ element }">
						<div class="drag-element" style="display: inline-block; width: 100px; height: 100px; margin: 10px; color: gray;">
							<el-image :src="element.url" :fit="'fill'" class="drag-img" style="width:100px;height:100px;"/>
							<div class="drag-btns">
									<el-row>
										<el-col :span="1"
											><el-button :text="true" @click="preview(element.url)" style="float: left"
												><el-icon><ZoomIn /></el-icon></el-button></el-col
										><el-col :span="20"></el-col>
										<el-col :span="1"
											><el-button :text="true" @click="remove(element)" style="float: right"
												><el-icon><Delete /></el-icon
											></el-button>
										</el-col>
									</el-row>
							</div>
						</div>
					</template>
					<template #footer>
						<div style="margin-top:30px;">
							<el-upload class="avatar-uploader" :action="state.uploadUrl" :show-file-list="false" :on-success="handleUploadSuccess" :before-upload="beforeUpload">
								<el-button type="primary">点击上传</el-button>
							</el-upload>
						</div>
					</template>
				</draggable>
			</el-col>
		</el-row>
		<el-row>
			<el-col :span="24">
				<span>上传的数据</span>
				<div>{{ state.fileList }}</div>
			</el-col>
		</el-row>
		<!--上传文件预览弹窗-->
		<el-dialog v-model="state.preview.visible">
			<el-image :src="state.preview.url" :fit="'fill'" />
		</el-dialog>
	</div>
</template>

<script setup name="dragsortupload">
import { defineAsyncComponent, reactive, onMounted, ref } from 'vue';
import { ElMessageBox, ElMessage } from 'element-plus';
import { ZoomIn, Plus, Delete } from '@element-plus/icons-vue';
import draggable from 'vuedraggable';

const state = reactive({
	uploadUrl:"",
	drag: true,
	preview: {
		visible:false,
		url: '',
	},
	fileList: [
		{
			id: 1,
			name: 'json',
			url: 'https://fuss10.elemecdn.com/3/63/4e7f3a15429bfda99bce42a18cdd1jpeg.jpeg?imageMogr2/thumbnail/360x360/format/webp/quality/100',
		},
		{ id: 2, name: 'jack', url: 'https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg' },
	],
});

const handleUploadSuccess = (response, uploadFile) => {
	console.log(response,uploadFile);
};

const beforeUpload = (rawFile) => {
	if (rawFile.type != 'image/jpeg') {
		ElMessage.error('Avatar picture must be JPG format!');
		return false;
	} else if (rawFile.size / 1024 / 1024 > 2) {
		ElMessage.error('Avatar picture size can not exceed 2MB!');
		return false;
	}
	// 以下为测试方法,实际使用过程中需要改成上传成功后再将返回结果放入fileList的操作
	state.fileList.push({id:rawFile.uid,name:rawFile.name,url:"https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg"});
	return true;
};

// 上传文件预览
const preview = (url) => {
	state.preview.visible = true
	state.preview.url = url
};

// 上传文件删除
const remove = (item) => {
	let index;
	let fileListTemp = state.fileList;
	for(let i=0;i<fileListTemp.length;i++){
		if(fileListTemp[i].id === item.id){
			index = i
		}
	}
	if(index){
		state.fileList.splice(index,1)
	}
};

// 页面加载时
onMounted(() => {});
</script>

<style scoped lang="scss">
.avatar-uploader .avatar {
	width: 178px;
	height: 178px;
	display: block;
}
</style>

<style>
.avatar-uploader .el-upload {
	border: 1px dashed var(--el-border-color);
	border-radius: 6px;
	cursor: pointer;
	position: relative;
	overflow: hidden;
	transition: var(--el-transition-duration-fast);
}

.avatar-uploader .el-upload:hover {
	border-color: var(--el-color-primary);
}

.el-icon.avatar-uploader-icon {
	font-size: 28px;
	color: #8c939d;
	width: 178px;
	height: 178px;
	text-align: center;
}
</style>

# Vue 

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×