最近接了一个需求,是把一个图片未识别列表,拖拽到详情列表里面相应的位置。详情列表的图片还能通过拖拽调整位置。
本来我想尝试使用 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>




