需求场景:
一、a-tree组件的拖拽排序
以下是通过a-tree组件渲染的树形结构,需求为同层级的节点可以拖拽排序,不可跨层级拖拽。
ant组件库示例展示了可跨层级的拖拽,这里只说明实现同层级拖拽的方法。
这里我参考网上资料写了一个实现同级拖拽的方法:
export function dropTree (info,gData) {
// 目标节点
const dropKey = info.node.eventKey;
// 拖动节点
const dragKey = info.dragNode.eventKey;
const dropPos = info.node.pos.split("-");
// -1 上
// 0 内
// 1 下
// 拖动的位置
const dropPosition = info.dropPosition - Number(dropPos[dropPos.length - 1]);
const loop = (data, key, callback) => {
data.forEach((item, index, arr) => {
if (item.id === key) {
return callback(item, index, arr);
}
if (item.children) {
return loop(item.children, key, callback);
}
});
};
const data = [...gData.value];
// 拖动节点的对象
let dragObj = {};
if (!info.dropToGap) {
return false;
} else if (
(info.node.children || []).length > 0 &&
info.node.expanded &&
dropPosition === 1
) {
return false;
} else {
let a = [];
let ii = 0;
loop(
data,
dragKey,
(item, index, arr) => {
a = arr;
ii = index;
dragObj = item;
}
);
// 只允许当前节点下的子节点拖动排序
if (a.some((item) => item.id === dropKey)) {
a.splice(ii, 1);
let ar = [];
let i = 0;
loop(
data,
dropKey,
(item, index, arr) => {
ar = arr;
i = index;
}
);
if (dropPosition === -1) {
ar.splice(i, 0, dragObj);
} else {
ar.splice(i + 1, 0, dragObj);
}
console.log(ar,'arrrrr');
return ar //本级排序后的数组
}
}
// return data 整个排序后的数组
}
这里我们的后端只要求传递改变排序后同层级的所有节点信息,所以我return的是 ar 这个数组,如果需要传递整个树形数组给后端则return data 这个数组即可
我的使用:
const onDrop = async (info) => { //info是拖动节点信息,组件自带的回调参数
if(!dropTree(info,treeData)) return message.warning('不可跨部门拖拽') //如果跨层级拖动则返回false
const sortTree = dropTree(info,treeData).map((item,index)=>{
return { //处理为后端需要的格式 这里的sort是后端要求前端自己做一个排序,所以直接取了Index值
id:item.id,
sort: index
}
}) //拖拽工具
// console.log(sortTree,'sortTree');
await getDrapSort(sortTree) //调用接口将排序后的节点数组传给后端
await depList() //刷新树形
}
二、普通div盒子的拖拽排序
a-tree组件自带了拖拽的属性,但是div是不能拖拽的,如果要手撸盒子的拿起与放下事件则非常复杂,这里采用vue自带的组件对要拖动的盒子进行包裹即可,不需要另外引入。
实现效果:
实现方法
/*事件相关*/
const dragstart= (value) => {
oldData = value
}
// 记录移动过程中信息
const dragenter = (value,e) =>{
newData = value
e.preventDefault()
}
// 拖拽最终操作
const dragend = async (value, e) => {
if (oldData !== newData) {
let oldIndex = jobList.value.indexOf(oldData)
let newIndex = jobList.value.indexOf(newData)
let newItems = [...jobList.value]
// 删除老的节点
newItems.splice(oldIndex, 1)
// 在列表中目标位置增加新的节点
newItems.splice(newIndex, 0, oldData)
jobList.value = [...newItems] //新排序的数组
}
const dropList = jobList.value.map((item,index) => { //处理为后端需要的格式
return {
id:item.id,
sort:index
}
})
console.log(dropList,'dropList');
await updateSort(dropList) //调用接口实现排序
await loadJobTitleList() // 刷新列表
}
// 拖动事件(主要是为了拖动时鼠标光标不变为禁止)
const dragover = (e) => {
e.preventDefault()
}