翼度科技»论坛 编程开发 JavaScript 查看内容

vue elementUi+sortable.js实现嵌套表格拖拽问题

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24
vue elementUi+sortable.js嵌套表格拖拽

首先说下项目需求,一个多层嵌套的表格,行可以进行拖拽排序,但不能跨主级去拖拽,下拉可以异步获取数据,考虑了很久,还是用最熟悉的vue+element来做,但是element没有拖拽排序的功能,所以在此基础上加入sortable.js去实现拖拽功能。
后台返回的排序规则是 每个数据都带有3个属性 id next prev
用这3个属性实时的去更新排序

  • id表示这一条数据的id
  • next表示下一条数据的id
  • prev表示上一条数据的id

html部分



data部分
  1. flattArray:[],
  2. originalData:[],
  3. tableData: [],
  4. arr:[],
  5. maps:new Map()
复制代码
我这里定义了四个数组和一个map
flattArray是平铺的数据 originalData数组也是平铺的数据(以防数据出错,没有啥实际用途) tableData是表格渲染的数据 arr是点击下拉异步请求的数据
maps是tableData改变后去重新渲染数据用的

methods部分

首先我定义了一个方法去深拷贝,这样改变一个数据的时候,其他数据不会改变
  1. //深拷贝
  2. getNewObject(val) {
  3.      let resObj = JSON.stringify(val);
  4.      return JSON.parse(resObj);
  5. },
复制代码
加载页面从接口 获取 tableData数据 并深拷贝 tableData
  1. getDetails(id){
  2.     axios.get(url).then(res =>{
  3.         if(res.data.code === 0){
  4.            this.tableData = res.data.data
  5.            this.tableData.map( item =>{
  6.              item.hasChildren = true
  7.              delete item.children
  8.            })
  9.            this.flattArray = this.getNewObject(this.tableData)
  10.            this.originalData = this.getNewObject(this.tableData)
  11.          }else{
  12.              this.$message.error('网络错误');
  13.         }
  14.    }).catch(function (error) {
  15.       this.$message.error('网络错误');
  16.    });
  17. },
复制代码
这里表格就已经渲染出来了 ,因为下拉的数据要异步去获取,所以在element提供的下拉事件里面去请求数据,这里去获取子级的数据,并给maps赋值,利用递归,把数据平铺、组装。
  1. //点击下拉图标异步加载数据
  2. load(tree, treeNode, resolve) {
  3.             this.maps.set(tree.id, { tree, treeNode, resolve })
  4.             axios.get(`url` + tree.id).then(res => {
  5.                 if (res.data.code == 0) {
  6.                     this.arr = res.data.data
  7.                     this.arr.map(item => {
  8.                         item.hasChildren = true
  9.                         delete item.children
  10.                         this.flattArray.push(item)
  11.                     })
  12.                     resolve(this.arr)
  13.                     const tree = buildTree(this.flattArray, 1);
  14.                     //组装tree
  15.                     function buildTree(nodes, parent) {
  16.                         const res = [];
  17.                         for (let item of nodes) {
  18.                             if (item.parentId === parent) {
  19.                                 const children = buildTree(nodes, item.id);
  20.                                 if (children.length) {
  21.                                     item.children = children;
  22.                                 }
  23.                                 res.push(item);
  24.                             }
  25.                         }
  26.                         return res;
  27.                     }
  28.                     //平铺tree
  29.                     let result = [];

  30.                     function flatTree(nodes, parentId) {
  31.                         if (!nodes || nodes.length === 0) return [];
  32.                         nodes.forEach(node => {
  33.                             result.push(node);
  34.                             return flatTree(node.children, node.id);
  35.                         });
  36.                     }
  37.                     flatTree(tree, 1);

  38.                     this.originalData = result
  39.                     this.getNewObject(this.originalData)
  40.                 } else {
  41.                     this.$message.error('没有更多消息了');
  42.                 }
  43.             })
  44.         },
复制代码
定义的行拖拽方法,因为排序是用的3个属性去排序的,所以有3种情况去考虑

  • 一是拖动到最上级,这样prev的值就为空
  • 二是拖动到最下级,next为空
  • 三是正常的拖动,next prev都不为空
  1. rowDrop() {
  2.             this.$nextTick(() => {
  3.                 const tbody = document.querySelector('.el-table__body-wrapper tbody')
  4.                 const _this = this
  5.                 Sortable.create(tbody, {
  6.                     animation: 300,
  7.                     sort: true,
  8.                     onEnd({
  9.                               oldIndex,
  10.                               newIndex,
  11.                               item
  12.                           }) {
  13.                         const sourceObj = _this.originalData[oldIndex - 1] // 原本的位置
  14.                         const targetObj = _this.originalData[newIndex - 1] // 移动到的位置
  15.                         const frontObj = _this.originalData[newIndex - 2] //移动后位置的上一级
  16.                         const behindObj = _this.originalData[newIndex] //移动后位置的下一级
  17.                         if(sourceObj.parentId != targetObj.parentId) {
  18.                             _this.$message.error("不支持跨级拖动,请拖回原来位置")
  19.                             location.reload();
  20.                             return;
  21.                         }
  22.                         let data = [];
  23.                         if( oldIndex < newIndex ){//向下移动
  24.                             //上一级
  25.                             let predata = {
  26.                                 id: targetObj.id,
  27.                                 next: sourceObj.id,
  28.                                 prev: targetObj.prev
  29.                             }
  30.                             //自己
  31.                             let curdata = {
  32.                                 id: sourceObj.id,
  33.                                 next: targetObj.next,
  34.                                 prev: targetObj.id,
  35.                                 groupId: sourceObj.groupId
  36.                             }
  37.                             //下一级
  38.                             let nextdata = null
  39.                             if (behindObj != undefined && sourceObj.parentId == behindObj.parentId) {
  40.                                 nextdata = {
  41.                                     id: behindObj.id,
  42.                                     next: behindObj.next,
  43.                                     prev: sourceObj.id
  44.                                 }
  45.                             }
  46.                             if(nextdata){
  47.                                 data.push(curdata, predata, nextdata)
  48.                             }else{
  49.                                 data.push(curdata, predata)
  50.                             }
  51.                             _this.postdata(data, sourceObj.parentId)
  52.                         }else if( oldIndex > newIndex ){//向上移动
  53.                             //上一级
  54.                             let predata = null
  55.                             if (frontObj != undefined && sourceObj.parentId == frontObj.parentId) {
  56.                                 predata = {
  57.                                     id: frontObj.id,
  58.                                     next: sourceObj.id,
  59.                                     prev: frontObj.prev
  60.                                 }
  61.                             }
  62.                             //自己
  63.                             let curdata = {
  64.                                 id: sourceObj.id,
  65.                                 next: targetObj.id,
  66.                                 prev: targetObj.prev,
  67.                                 groupId: sourceObj.groupId
  68.                             }
  69.                             //下一级
  70.                             let nextdata = {
  71.                                 id: targetObj.id,
  72.                                 next: targetObj.next,
  73.                                 prev: sourceObj.id
  74.                             }

  75.                             if(predata){
  76.                                 data.push(curdata, predata, nextdata)
  77.                             }else{
  78.                                 data.push(curdata, nextdata)
  79.                             }
  80.                             _this.postdata(data, sourceObj.parentId)
  81.                         }
  82.                     }
  83.                 })
  84.             })
  85.         },
复制代码
mounted 里面去加载 改变行的方法
  1. mounted() {
  2.           this.rowDrop()
  3. },
复制代码
最后再去动态的更新数据
  1. refreshLoadTree(parentId) {
  2.             // 根据父级id取出对应节点数据
  3.             const {tree, treeNode, resolve} = this.maps.get(parentId)
  4.             this.$set(this.$refs.tableData.store.states.lazyTreeNodeMap, parentId, [])
  5.             if (tree) {
  6.                 this.load(tree, treeNode, resolve)
  7.             }
  8.         },
复制代码
到这里需求已经实现了,就没有去深入的挖掘,可能会有问题,但是隔的时间太久了,基本忘光了。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

来源:https://www.jb51.net/javascript/322400cb3.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具