Element-UI控件Tree实现数据树形结构
在前端开发中,有时会遇到所有菜单数据在同一级的情况,后端未对数据进行分级处理;但前端渲染需要是树状结构的数据,如何实现数据的树状化?将数组中通过父节点的ID与子节点的parentId关联,通过递归函数来实现。
前端框架这里使用element-ui的tree控件来实现,对其不了解可以去官网查看文档。
地址:Element - The world's most popular Vue UI framework
一、创建页面
这里就不讲vue项目的搭建了,基础不好的,可以去官网查看文档。
首先在src/pages目录中,创建element-trees文件夹,再创建index.vue,代码如下:
在类选择器tree-container容器中,添加相关按钮和Tree控件,以及给容器添加些样式进行修饰一下,代码如下:
添加菜单 删除选中项 {{ node.label }}添加 修改 删除
此时页面效果如下:

二、模拟数据
在element-trees文件夹中添加data.js文件,用来存储模拟数据。代码如下:
/*** 模拟数据*/
const dataList = [{"name": "网络安全渗透工程师体系大纲","pid": 0,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 1},{"name": "WEB通信、前后端原理","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 2},{"name": "信息收集","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 3},{"name": "注入全方位利用+数据库注入","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 4},{"name": "前端渗透、文件上传解析漏洞","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 5},{"name": "漏洞利用","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 6},{"name": "漏洞挖掘","pid": 1,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 7},{"name": "Web服务器通信原理","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 8},{"name": "后端基础SQL","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 9},{"name": "数据库简介及SQL语法","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 10},{"name": "后端基础SQL高级查询与子查询","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 11},{"name": "后端基础PHP简介及基本函数上","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 12},{"name": "后端基础PHP—表单验证","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 13},{"name": "正则表达式","pid": 2,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 14},{"name": "信息搜集的意义 — 渗透测试的灵魂","pid": 3,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 15},{"name": "信息收集(一)","pid": 3,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 16},{"name": "网络架构-信息收集","pid": 3,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 17},{"name": "前端-信息收集","pid": 3,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 18},{"name": "系统-信息收集","pid": 3,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 19},{"name": "SQL注入的原理","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 20},{"name": "渗透测试常用工具讲解","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 21},{"name": "POST注入/HEAD注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 22},{"name": "盲注","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 23},{"name": "XSS的原理分析与解剖","pid": 5,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 24},{"name": "存储型XSS","pid": 5,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 25},{"name": " Dom Based XSS","pid": 5,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 26},{"name": "XXE实体注入","pid": 6,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 27},{"name": "SSRF-服务器端请求伪造","pid": 6,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 28},{"name": "验证码绕过、密码找回漏洞","pid": 7,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 29},{"name": "平行越权、垂直越权","pid": 7,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 30},{"name": "支付漏洞","pid": 7,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 31},{"name": "Sql注入","pid": 7,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 32},{"name": "变量覆盖漏洞","pid": 6,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 33},{"name": "本地包含与远程包含","pid": 6,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 34},{"name": "unserialize反序列化漏洞","pid": 6,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 35},{"name": "CSRF","pid": 5,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 36},{"name": "文件上传解析漏洞","pid": 5,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 37},{"name": "宽字节注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 38},{"name": "Accsess注入 — Cookie注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 39},{"name": "Accsess注入 — 偏移注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 40},{"name": "MySQL注入 — Dns 注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 41},{"name": "MSSQL注入 — 反弹注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 42},{"name": "Oracle注入 — 报错注入","pid": 4,"createtime": "2023-03-29","updatetime": "2023-03-29","id": 43}
];export default dataList;
文件创建好后,我们将其引入到index.vue文件中,代码如下:
如上代码,通过loadNode()函数执行后,模拟数据则已与Tree控件进行了双方绑定。但是页面中显示的数据,全都显示在同级位置。数据的归类分级,我们在后面再讲解。页面效果如下:

三、递归函数
此时离成功紧一步之遥了,我们先来分析下data.js中的数据结构。如下图:

如何将数据归类分级呢,可以通过循环判断,每级的id与数据中的pid进行关联;比如第一条数据id为1,将数组进行遍历查询判断pid有为1的数据,则表示其有子项数据,将其子项数据添加到children数组中。pid为0的为一级数据,所以当定义递归函数时,传入的pid默认为0。
这里层次有可能是1层,2层,3层...... n层,要一层一层循环判断,就太麻烦了;所以这里我们要使用递归方法,来实现n层级的数据处理。
在src下创建utils/utils.js文件,在utils.js中定义递归函数,代码如下:
/*** 递归函数* @param arr 数组* @param pid 父ID,不传默认为0*/
export const DGFilterTrees = (arr, pid = 0) => {let newArr = [];//循环数组arr.forEach((item, i) => {//判断pid与遍历元素中pid相同的数据,相等的为同级数据,追加到该级数组中if(item.pid == pid){newArr.push(item);/*** 判断该item元素是否有子项* 当数组中有元素的pid与item.id相等,some函数会返回true,表示该元素有子项数据*/if(arr.some(ele => ele.pid == item.id)){//此时,通过重新调用本函数进行递归处理item['children'] = DGFilterTrees(arr, item.id);}}});return newArr;
}
注:递归算法是一种直接或者间接调用自身函数或者方法的算法。
递归算法的特点:
- 递归就是方法里调用自身。
- 在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。
- 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。
- 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等,所以一般不提倡用递归算法设计程序。
所以在使用递归算法时,一定要注意判断条件能正常退出,否则无法靠自身的控制终止的循环,会导致栈溢出,程序卡死等问题。
将DGFilterTrees()递归函数引入到index.vue中,将模拟数据重组,代码如下:
此时,所有数据都进行了归类分级显示,页面的效果图如下:

四、选中后显示按钮
如上图,我们会发现每项后面的添加、修改、删除全显示出来,会显示拥挤并不方便操作。这里我们将节点输出后会发现,可以使用isCurrent来判断,只显示选中当前项的按钮。

在span标签上添加v-if,判断node.isCurrent是否为true,代码如下:
{{ node.label }}添加 修改 删除
如下图,点击选择”后端基础SQL“后,会显示后面的操作按钮。

五、删除元素
这里我们是使用本地定义模拟数据进行操作的,所以没有真实项目中是通过接口进行数据的增删改查部分。代码如下:
//移出项目
remove(node, data){if(Array.isArray(data['children'])&&data.children.length>0){this.$message.error('当前数据有子项,无法删除~');return;}//查询数据位置索引let index = DataList.findIndex(item => item.id==data.id);//删除指定位置数据DataList.splice(index, 1);//重新加载数据this.loadNode();
}
效果如下图:

五、删除多选项
这里需要使用Tree控件的getCheckedNodes()函数,来获取被选中项;然后通过循环,删除每条被选中元素,代码如下:
//删除选中的节点
removeSelected(){//获取选中的数据let checks = this.$refs.tree.getCheckedNodes();//循环删除选中checks.forEach(item => {DataList.splice(DataList.findIndex(sub => sub.id == item.id), 1);});//重新加载数据this.loadNode();
}
效果如下图:

本期就先介绍到这,添加、修改等功能也比较简单,可以通过element-ui的$prompt弹框控件来实现。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
