实现a-tree树形的拖拽排序与普通div盒子的拖拽排序

955 阅读2分钟

需求场景:

一、a-tree组件的拖拽排序

以下是通过a-tree组件渲染的树形结构,需求为同层级的节点可以拖拽排序,不可跨层级拖拽。

微信图片_20230302141101.png

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 这个数组即可

我的使用:

微信图片_20230302142236.png

 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自带的组件对要拖动的盒子进行包裹即可,不需要另外引入。 实现效果: 微信图片_20230302142914.png

实现方法

微信图片_20230302143358.png

    /*事件相关*/
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()
}