目的是在已有组件基础 或 自己手写列表 实现可拖动排序
思路
1.vue 是数据驱动视图 所以 改变数据就改变视图,所以拖动排序是操作数据就可实现
2.通过 原生js 获取所有即将拖动的元素,然后添加拖动事件 draggable是否能拖动、dragstart被拖动元素触发、drop放下到目标元素触发、dragover拖动到目标元素上触发
3.给遍历每个参与拖动的元素 用 setAttribute 加上 索引,这个索引对应 原来渲染用的数组索引,通过触发 拖拽事件 操作数组
/**
* 拖动列表排序 获取所有参与拖动的最外层元素,并通过js添加 拖动事件。 添加事件前先清下之前添加的事件,每次添加监听事件都会占用内存避免泄漏
*/
addEvent(){
// domList
let domList = document.getElementsByClassName('ant-upload-list-picture-card-container')
for(let i = 0; i < domList.length; i++){
let domItem = domList[i]
domItem.draggable = false;
domItem.style.cursor = 'auto';
domItem.removeEventListener('dragstart',this.drag)
domItem.removeEventListener('drop',this.drop)
domItem.removeEventListener('dragover',this.allowDrop)
}
for(let i = 0; i < domList.length; i++){
let domItem = domList[i]
domItem.draggable = true;
domItem.setAttribute('data-index',i);
domItem.style.cursor = 'all-scroll';
domItem.addEventListener('dragstart',this.drag, false) // 开始拖元素触发,作用于拖拽元素
domItem.addEventListener('drop',this.drop, false) // 当元素放下到drop元素触发,作用于目标元素
domItem.addEventListener('dragover',this.allowDrop, false) // 当元素拖动到drop元素上时触发,作用于目标元素
}
},
// 开始拖元素触发,作用于拖拽元素
drag(event) {
event.dataTransfer.setData('index', event.target.dataset.index );
},
// 当元素放下到drop元素触发,作用于目标元素
drop(event) {
console.log(event,event.srcElement.getAttribute('data-index'))
event.preventDefault();
event.stopPropagation();
let startIndex = parseInt(event.dataTransfer.getData('index')),
trNode = this.handleGetTrNode(event.target),
trIndex = trNode.getAttribute('data-index'),
currentIndex = parseInt(trIndex);
// console.log("start", startIndex);
// console.log("drop", currentIndex);
if (startIndex - currentIndex > 0) {
// console.log("要拖拽的元素的索引 大于 当前位置的元素的索引");
this.fileList.splice(currentIndex, 0, this.fileList[startIndex]);
// console.log("删除" + startIndex + 1);
this.fileList.splice(startIndex + 1, 1)
} else if (startIndex - currentIndex < 0) {
// console.log("要拖拽的元素的索引 小于 当前位置的元素的索引");
this.fileList.splice(currentIndex + 1, 0, this.fileList[startIndex]);
this.fileList.splice(startIndex, 1)
} else {
// console.log("什么也不用做");
}
},
// 当元素拖动到drop元素上时触发,作用于目标元素
allowDrop(event) {
event.preventDefault();
event.stopPropagation();
},
// 防止拖拽松开时 落在子元素上,递归找到目标元素。ob.className 只是一种获取目标元素的形式 也可也是其它方式
handleGetTrNode(ob) {
console.log(ob.className)
if(ob.className == 'ant-upload-list-picture-card-container'){
return ob
} else{
return this.handleGetTrNode(ob.parentNode)
}
},