最近接了一个需求,是把一个图片未识别列表,拖拽到详情列表里面相应的位置。详情列表的图片还能通过拖拽调整位置。
本来我想尝试使用 vuedraggable, 但是发现,通过查看官方demo,和搜索发现 ,vuedraggable 会拖动整个项,难以满足我只想图片被拖动的效果(有可能我没研究透彻)。总之自由度不是很高。后面发现了原生APi。
HTML5 的原生拖拽 API(Drag and Drop API)来实现自定义的拖拽效果。raggable 属性和相应的事件处理程序来控制拖拽的行为。自由度大大提升。@dragstart、@dragover、@dragenter、@dragleave、@drop和@dragend等事件监听器来处理拖拽的不同阶段。话不多说上代码。
<template> <div class="page-container"> <div class="section"> <div class="left-section"> <div class="section-title">{{ isEdit ? "修改详情" : "查看详情" }}</div> <div class="info-list"> <div class="list-item"> <div class="lf_title">学员名称:</div> <div class="rt_value">{{ info.name }}</div> </div> <div class="list-item"> <div class="lf_title">身份证:</div> <div class="rt_value">{{ info.idcard }}</div> </div> <div v-for="(item, index) in recognizedImagesLists" :key="item.key" class="list-item" :draggable="true" @dragstart="handleDragStart(index, 1)" @dragend="handleDragEnd" @dragover="handleDragOver" @drop="handleDrop(index, 1)" > <div class="lf_title nomove">{{ item.label }}:</div> <div class="rt_value"> <template v-if="item.imageUrl"> <el-image :src="item.imageUrl" style="height: 150px"></el-image> </template> <template v-if="!item.imageUrl"> <el-image style="height: 150px;width: 200px;"> <div slot="error" class="image-slot"> <i class="el-icon-picture-outline" style="fontSize:24px" ></i> </div> </el-image> </template> </div> </div> </div> </div> <div class="right-section"> <div>未识别图片</div> <div class="img-lists" v-if="UnrecognizedImagesLists && UnrecognizedImagesLists.length > 0" > <div class="img-item" v-for="(item, index) in UnrecognizedImagesLists" :key="index" :draggable="true" @dragstart="handleDragStart(index, 2)" @dragend="handleDragEnd" @dragover="handleDragOver" @drop="handleDrop(index, 2)" > <el-image :src="item.imageUrl" style="width: 150px"> </el-image> </div> </div> </div> </div> <div class="btn-part" v-show="isEdit"> <el-button @click="saveDetail" type="primary">确认</el-button> <el-button @click="isEdit = false">取消</el-button> </div> </div> </template> <script> export default { data() { return { isEdit: false, // 基础信息 info: { name: "邓xx", idcard: "44011119xxx25730" }, //已匹配 recognizedImagesLists: [ { key: "idcardImg", label: "身份证(照片)", imageUrl: "" }, { key: "cer", label: "学历", imageUrl: require("../assets/img/temp/cer.png") }, { key: "men", label: "半身照", imageUrl: require("../assets/img/temp/m.png") }, { key: "sign", label: "个人签名", imageUrl: "" } ], dragData: null, //未匹配 UnrecognizedImagesLists: [ { id: 1, imageUrl: require("../assets/img/temp/idcard.png") }, { id: 2, imageUrl: require("../assets/img/temp/qm.png") } ] }; }, created() { }, methods: { /** * 拖拽开始时的索引 , 记录初始拖拽的index * @param {Number} index * @param {Number} listindex */ handleDragStart(index, listIndex) { this.dragData = { index, listIndex }; }, /** * 阻止了默认的拖拽行为 * @param {*} event */ handleDragOver(event) { event.preventDefault(); }, /** * 拖拽中 * @param {Number} index 结束时的数组下标 * @param {Number} listindex */ handleDrop(index, listindex) { console.log("开始的index", this.dragData.index); console.log("结束的index", index); if (this.dragData && this.dragData.listIndex) { const startIndex = this.dragData.index; const startListsIndex = this.dragData.listIndex; if (startListsIndex == listindex) { //同列拖拽 已识别->已识别 const tempImageUrl = this.recognizedImagesLists[index].imageUrl; this.recognizedImagesLists[ index ].imageUrl = this.recognizedImagesLists[startIndex].imageUrl; this.recognizedImagesLists[startIndex].imageUrl = tempImageUrl; //拖拽完成时交换了拖拽项的位置 } else { //异列拖拽 未识别->已识别 const unImageUrl = this.UnrecognizedImagesLists[startIndex].imageUrl; this.UnrecognizedImagesLists.splice(startIndex, 1); this.recognizedImagesLists[index].imageUrl = unImageUrl; } } }, /** * 拖拽结束 重置了拖拽索引 */ handleDragEnd() { this.dragData = null; } } }; </script> <style lang="less" scoped> .page-container { .header-btns { padding: 0 50px; margin: 20px 0 30px; display: -webkit-flex; display: flex; -webkit-justify-content: space-between; justify-content: space-between; } .section-title { font-weight: 600; } .section { display: flex; justify-content: space-between; .left-section { width: 600px; .info-list { padding-left: 30px; width: 100%; .list-item { display: flex; width: 100%; margin-block: 20px; .lf_title { width: 150px; text-align: right; font-weight: bold; flex-shrink: 0; } .rt_value { width: 450px; } } } } .right-section { width: 400px; border: 1px solid; padding: 20px; } } .btn-part { text-align: center; margin-top: 50px; } /deep/ .image-slot { display: flex; justify-content: center; align-items: center; width: 100%; height: 100%; background: #f5f7fa; color: #909399; } } </style>