VUE el-tree组件左边勾选,右边清除交互

最近做了一个类似于目录树的一个功能,

  1. UI框架:ElementUI
  2. Vue: vue2
  • 如下展示的是代码的实现思路和过程

需求如下:

1.树形左侧展示的是最顶层的name,右侧展示的是它所有的子集

2.最右侧的"已选多少项"展示的是选中的子集和它的父级,如果选中的子集有多项 则放入相同的父级下,删除子集同步取消左侧的选中状态

3.最后选中的数据保存的时候 需要跟源数据进行对比,去除未选中的子集和父级,一直找到根节点

  • 思路:

1.首先数据已经确定,树形结构数据。

2.其次我要进行将子集中的父级置为不可选的状态,还要考虑到父子不关联,我想到用 Element ui树型结构中props去处理 将所有children不为空的数据进行disabled 禁用掉。

3.接下来需要处理的是子集选中并放入某一个空数组并用于展现右侧已选中的视图

4.数据最后的保存采用递归进行对比,排除未选中的数据,大体思路就是这样

下面展示的图片是初始状态

展示代码:

首先 "我的数据"代码:

js 复制代码
<div >
      <div 
      v-for="(lfdata, lfindex) in cdlist" :key="lfindex">
      checked:用于选中状态
      <span :style="{ backgroundColor: lfindex == checkcd ? '#2C76E4' : '', color: lfindex == checkcd ? '#fff' : '#000' }"  @click="lfclick(lfindex, lfdata)">{{lfdata.name}}</span></div>
</div>
<div  class="defaultProps">
  <el-tree :data="datadata" show-checkbox default-expand-all node-key="code"
 ref="tree" highlight-current :filter-node-method="filterNode":props="defaultProps" @check="getdatalist"></el-tree>
</div>

"已选多少项"代码:

js 复制代码
<div><div style="display: flex;justify-content: space-between;padding:10px;">
 <p>已选<span >{{ rightlength}}</span>项</p> <span v-if="allchildcode.length > 0 " @click="closeAll">清空</span></div>
  <div>
  <ul v-if="filterParent.length > 0"><li class="ivu-timeline-item" v-for="(item, index) in filterParent" :key="index"><div class="ivu-timeline-item-tail">
</div><div v-if="(index + 1) != filterParent.length"></div>
<div class="ivu-timeline-item-content" ><div ><div>{{ item.name }} </div>
                                                        <Tag v-for="item1 in item.children" :key="item1.code"
                                                            :name="item1.code" 
                                                            color="primary" @on-close="tagclose(item1)">
                                                            <Tooltip :content="item1.name" placement="top-left">
                                                                {{ item1.name }}</Tooltip>
                                                        </Tag>
                                                    </div>
                                                </div>
                                            </li>
                                        </ul>
                                        <ul v-else style="text-align: center;">
                                            暂无数据
                                        </ul>
                                    </div>
                                </div>

事件代码如下:

js 复制代码
该方法是选中子集进行数据提取并放入新数组,进行了数据的处理
 getdatalist(nodeObj, nodeState) {
            let isCheck = this.$refs.tree.getCheckedNodes().indexOf(nodeObj) > -1;
            if (isCheck) {
                
                this.findDataById(nodeObj.parentId, this.datadata, 'result')
                this.filterparentcode(this.result, nodeState.checkedNodes, this.filterParent)

            } else {
                该方法是同步取消右侧已选数据 
                this.tagclose(nodeObj)
            }
            
        },
        
        //递归查找parentid
        findDataById(id, data1, result) {
            this[result] = []; // 清空上一次的结果
            const traverse = (data) => {
                for (const item of data) {
                    if (item.code === id) {
                        this[result].push(item);
                    }
                    if (item.children) {
                        traverse(item.children);
                    }
                }
            };

            traverse(data1);
        },
        
        //  递归查找所有的父节点code,根据父节点code将子集放入children
        filterparentcode(a, b, c) {
            let data = JSON.parse(JSON.stringify(a[0]))
            let arr = [];
            b.forEach((item, index) => {
                if (item.parentId == data.code) {
                    arr.push(item)
                }
            });
            data.children = arr;
            if (c.length > 0) {
                let dataparentindex = "";
                c.forEach((item, index) => {
                    if (item.code == data.code) {
                        dataparentindex = index;
                    }
                });
                if (/^[0-9]+.?[0-9]*$/.test(dataparentindex)) {
                    c[dataparentindex].children = data.children;
                } else {
                    c.push(data)
                }
            } else {
                c.push(data)
            }
        },
        右侧 取消事件
         tagclose(event, type) {
          this.$refs.tree.setChecked(event.code, false, false);
                    this.checkedNodesdata = this.findLeafNodes(this.$refs.tree.getCheckedNodes())
                    this.checkedNodesdata = [...new Set(this.checkedNodesdata)]
                    let parenta = this.findParentNode(JSON.parse(JSON.stringify(this.quanxuandata)), this.checkedNodesdata);
                    parenta = [...new Set(parenta)]
                    console.log(parenta);
                    let parentall = this.regroup(parenta, JSON.parse(JSON.stringify(this.checkedNodesdata)))
                    this.filterParent = parentall;
         }
         
          //查找叶子节点
         findLeafNodes(tree) {
            const leafNodes = [];
            // 递归函数,用于遍历树节点
            const traverseTree = (node) => {
                if (!node.children || node.children.length === 0) {
                    // 没有子节点,将当前节点添加到叶节点数组中
                    leafNodes.push(node);
                } else {
                    // 有子节点,继续遍历子节点
                    node.children.forEach(traverseTree);
                }
            };
            // 遍历整个树结构
            tree.forEach(traverseTree);

            return leafNodes;
        },
        //查找父级节点
         findParentNode(tree, parentId) {
            if (tree.code === parentId) {
                return tree;
            }
            if (tree.children) {
                for (let i = 0; i < tree.children.length; i++) {
                    const parent = this.findParentNode(tree.children[i], parentId);
                    if (parent) {
                        return parent;
                    }
                }
            }
            if (Array.isArray(tree)) {
                for (let i = 0; i < tree.length; i++) {
                    const parent = this.findParentNode(tree[i], parentId);
                    if (parent) {
                        return parent;
                    }
                }
            }
            return null;
        },
        
        
        

"已选多少项"最后数据结构如下:

js 复制代码
  data: [
  { id: 1, label: '一级 1', children: [{ id: 4, label: '二级 1-1', children: [{ id: 9, label: '三级 1-1-1' }, { id: 10, label: '三级 1-1-2' }] }] }, { id: 2, label: '一级 2', children: [{ id: 5, label: '二级 2-1' }, { id: 6, label: '二级 2-2' }] }, { id: 3, label: '一级 3', children: [{ id: 7, label: '二级 3-1' }, { id: 8, label: '二级 3-2' }] }
  ],

最后在进行跟源数据对比去除未选中的数据:

js 复制代码
数据提取  提出来所有的code
 findAllParentNodeCodes(tree, childNodeCode, options = {}) {
            const { children = 'children', code = 'code' } = options;
            let result = [];

            // 递归函数,查找所有父节点code和选中子节点code
            const findNodeCodesRecursive = (node, parentCodes = []) => {
                if (node[children]) {
                    for (let i = 0; i < node[children].length; i++) {
                        const childNode = node[children][i];
                        if (childNode[code] === childNodeCode) {
                            result = [...parentCodes, node[code], childNodeCode];
                            return true; // 已找到目标节点,返回true
                        } else {
                            if (findNodeCodesRecursive(childNode, [...parentCodes, node[code]])) {
                                return true; // 已找到目标节点,返回true
                            }
                        }
                    }
                }
                return false; // 未找到目标节点,返回false
            };

            // 查找根节点
            for (let i = 0; i < tree.length; i++) {
                const node = tree[i];
                if (!node[children] && node[code] === childNodeCode) {
                    return [node[code]]; // 子节点就是根节点,返回只包含根节点code的数组
                }
                if (findNodeCodesRecursive(node)) {
                    return result;
                }
            }

            return result;
        },
        过滤后最终得到的数据
         filterTreeByArray(tree, codeArray) {
            const childrenKey = 'children';
            // 递归函数,过滤非目标节点和子节点
            const filterNode = (node) => {
                if (codeArray.includes(node.code)) {
                    if (node[childrenKey]) {
                        node[childrenKey] = node[childrenKey].filter(filterNode);
                        return true; // 返回true表示保留当前节点
                    }
                    return true;
                }
                return false; // 返回false表示过滤掉当前节点
            };
            // 遍历整个树结构,并返回过滤后的树
            return tree.filter(filterNode);
        },

以上就是整个业务代码,欢迎大家提出自己更好的建议。

相关推荐
独泪了无痕34 分钟前
CryptoJS:数据安全的JavaScript加密利器
前端·vue.js·node.js
熊猫_豆豆2 小时前
一个模拟四轴飞行器在随机气流扰动下悬停飞行的交互式3D仿真网页,包含飞行器建模与PID控制算法
javascript·3d·html·四轴无人机模拟飞行
来恩10033 小时前
jQuery选择器
前端·javascript·jquery
前端繁华如梦3 小时前
树上挂苹果还是挂玻璃球?Three.js 程序化果实的完整实现指南
前端·javascript
CDwenhuohuo4 小时前
优惠券组件直接用 uview plus
前端·javascript·vue.js
川冰ICE4 小时前
TypeScript装饰器与元编程实战
前端·javascript·typescript
AI砖家4 小时前
Vue3组件传参大全,各种传参方式的对比
前端·javascript·vue.js
希望永不加班4 小时前
var局部变量类型推断的利弊
java·服务器·前端·javascript·html
threelab5 小时前
Three.js 3D 地图可视化 | 三维可视化 / AI 提示词
前端·javascript·人工智能·3d·着色器
爱怪笑的小杰杰5 小时前
Leaflet 高性能大数据量图圆:彻底解决缩放/拖拽偏移问题
大数据·前端·vue.js·贴图