免费资源网,https://freexyz.cn/
目录
  • vue elementUi+sortable.js嵌套表格拖拽
    • html部分
    • data部分
    • methods部分
  • 总结

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

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

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

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

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

    html部分

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

    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)
                }
            },

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

    总结

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

    免费资源网,https://freexyz.cn/
    声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。