当前位置: 代码网 > it编程>前端脚本>Vue.js > vue elementUi+sortable.js实现嵌套表格拖拽问题

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

2024年06月10日 Vue.js 我要评论
vue elementui+sortable.js嵌套表格拖拽首先说下项目需求,一个多层嵌套的表格,行可以进行拖拽排序,但不能跨主级去拖拽,下拉可以异步获取数据,考虑了很久,还是用最熟悉的vue+el

vue elementui+sortable.js嵌套表格拖拽

首先说下项目需求,一个多层嵌套的表格,行可以进行拖拽排序,但不能跨主级去拖拽,下拉可以异步获取数据,考虑了很久,还是用最熟悉的vue+element来做,但是element没有拖拽排序的功能,所以在此基础上加入sortable.js去实现拖拽功能。

后台返回的排序规则是 每个数据都带有3个属性 id next prev 

用这3个属性实时的去更新排序

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

html部分

data部分

 flattarray:[],
 originaldata:[],
 tabledata: [],
 arr:[],
 maps:new map()

我这里定义了四个数组和一个map

flattarray是平铺的数据 originaldata数组也是平铺的数据(以防数据出错,没有啥实际用途) tabledata是表格渲染的数据 arr是点击下拉异步请求的数据

maps是tabledata改变后去重新渲染数据用的

methods部分

首先我定义了一个方法去深拷贝,这样改变一个数据的时候,其他数据不会改变

 //深拷贝
 getnewobject(val) {
     let resobj = json.stringify(val);
     return json.parse(resobj);
 },

加载页面从接口 获取 tabledata数据 并深拷贝 tabledata

getdetails(id){
    axios.get(url).then(res =>{
        if(res.data.code === 0){
           this.tabledata = res.data.data
           this.tabledata.map( item =>{
             item.haschildren = true
             delete item.children
           })
           this.flattarray = this.getnewobject(this.tabledata)
           this.originaldata = this.getnewobject(this.tabledata)
         }else{
             this.$message.error('网络错误');
        }
   }).catch(function (error) {
      this.$message.error('网络错误');
   });
},

这里表格就已经渲染出来了 ,因为下拉的数据要异步去获取,所以在element提供的下拉事件里面去请求数据,这里去获取子级的数据,并给maps赋值,利用递归,把数据平铺、组装。

//点击下拉图标异步加载数据
load(tree, treenode, resolve) {
            this.maps.set(tree.id, { tree, treenode, resolve })
            axios.get(`url` + tree.id).then(res => {
                if (res.data.code == 0) {
                    this.arr = res.data.data
                    this.arr.map(item => {
                        item.haschildren = true
                        delete item.children
                        this.flattarray.push(item)
                    })
                    resolve(this.arr)
                    const tree = buildtree(this.flattarray, 1);
                    //组装tree
                    function buildtree(nodes, parent) {
                        const res = [];
                        for (let item of nodes) {
                            if (item.parentid === parent) {
                                const children = buildtree(nodes, item.id);
                                if (children.length) {
                                    item.children = children;
                                }
                                res.push(item);
                            }
                        }
                        return res;
                    }
                    //平铺tree
                    let result = [];
 
                    function flattree(nodes, parentid) {
                        if (!nodes || nodes.length === 0) return [];
                        nodes.foreach(node => {
                            result.push(node);
                            return flattree(node.children, node.id);
                        });
                    }
                    flattree(tree, 1);
 
                    this.originaldata = result
                    this.getnewobject(this.originaldata)
                } else {
                    this.$message.error('没有更多消息了');
                }
            })
        },

定义的行拖拽方法,因为排序是用的3个属性去排序的,所以有3种情况去考虑

  • 一是拖动到最上级,这样prev的值就为空
  • 二是拖动到最下级,next为空
  • 三是正常的拖动,next prev都不为空
 rowdrop() {
            this.$nexttick(() => {
                const tbody = document.queryselector('.el-table__body-wrapper tbody')
                const _this = this
                sortable.create(tbody, {
                    animation: 300,
                    sort: true,
                    onend({
                              oldindex,
                              newindex,
                              item
                          }) {
                        const sourceobj = _this.originaldata[oldindex - 1] // 原本的位置
                        const targetobj = _this.originaldata[newindex - 1] // 移动到的位置
                        const frontobj = _this.originaldata[newindex - 2] //移动后位置的上一级
                        const behindobj = _this.originaldata[newindex] //移动后位置的下一级
                        if(sourceobj.parentid != targetobj.parentid) {
                            _this.$message.error("不支持跨级拖动,请拖回原来位置")
                            location.reload();
                            return;
                        }
                        let data = [];
                        if( oldindex < newindex ){//向下移动
                            //上一级
                            let predata = {
                                id: targetobj.id,
                                next: sourceobj.id,
                                prev: targetobj.prev
                            }
                            //自己
                            let curdata = {
                                id: sourceobj.id,
                                next: targetobj.next,
                                prev: targetobj.id,
                                groupid: sourceobj.groupid
                            }
                            //下一级
                            let nextdata = null
                            if (behindobj != undefined && sourceobj.parentid == behindobj.parentid) {
                                nextdata = {
                                    id: behindobj.id,
                                    next: behindobj.next,
                                    prev: sourceobj.id
                                }
                            }
                            if(nextdata){
                                data.push(curdata, predata, nextdata)
                            }else{
                                data.push(curdata, predata)
                            }
                            _this.postdata(data, sourceobj.parentid)
                        }else if( oldindex > newindex ){//向上移动
                            //上一级
                            let predata = null
                            if (frontobj != undefined && sourceobj.parentid == frontobj.parentid) {
                                predata = {
                                    id: frontobj.id,
                                    next: sourceobj.id,
                                    prev: frontobj.prev
                                }
                            }
                            //自己
                            let curdata = {
                                id: sourceobj.id,
                                next: targetobj.id,
                                prev: targetobj.prev,
                                groupid: sourceobj.groupid
                            }
                            //下一级
                            let nextdata = {
                                id: targetobj.id,
                                next: targetobj.next,
                                prev: sourceobj.id
                            }
 
                            if(predata){
                                data.push(curdata, predata, nextdata)
                            }else{
                                data.push(curdata, nextdata)
                            }
                            _this.postdata(data, sourceobj.parentid)
                        }
                    }
                })
            })
        },

mounted 里面去加载 改变行的方法

 mounted() {
          this.rowdrop()
 },

最后再去动态的更新数据

refreshloadtree(parentid) {
            // 根据父级id取出对应节点数据
            const {tree, treenode, resolve} = this.maps.get(parentid)
            this.$set(this.$refs.tabledata.store.states.lazytreenodemap, parentid, [])
            if (tree) {
                this.load(tree, treenode, resolve)
            }
        },

到这里需求已经实现了,就没有去深入的挖掘,可能会有问题,但是隔的时间太久了,基本忘光了。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com