Element控件Tree实现数据树形结构的示例代码

 更新时间:2023年08月01日 10:06:47   作者:觉醒法师  
我们在开发中肯定会遇到用树形展示数据的需求,本文主要介绍了Element控件Tree实现数据树形结构的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

在前端开发中,有时会遇到所有菜单数据在同一级的情况,后端未对数据进行分级处理;但前端渲染需要是树状结构的数据,如何实现数据的树状化?将数组中通过父节点的ID与子节点的parentId关联,通过递归函数来实现。

前端框架这里使用element-ui的tree控件来实现,对其不了解可以去官网查看文档。

地址:Element - The world's most popular Vue UI framework

一、创建页面

这里就不讲vue项目的搭建了,基础不好的,可以去官网查看文档。

首先在src/pages目录中,创建element-trees文件夹,再创建index.vue,代码如下:

<template>
  <div class="tree-container">
  </div>
</template>
<script>
  export default {
    data(){
      return {}
    },
    created() {},
    methods: {}
  }
</script>
<style lang="scss">
</style>

在类选择器tree-container容器中,添加相关按钮和Tree控件,以及给容器添加些样式进行修饰一下,代码如下:

<template>
  <div class="tree-container">
    <div class="top-box">
      <el-button type="primary" size="mini" @click="appendNode">添加菜单</el-button>
      <el-button type="info" size="mini" @click="removeSelected">删除选中项</el-button>
    </div>
    <el-tree
    	ref="tree"
    	:data="treeData"
    	:props="props"
    	accordion
    	show-checkbox
    	node-key="id"
    	default-expand-all
    	:expand-on-click-node="false">
    	<span class="custom-tree-node" slot-scope="{ node, data }">
    		<span>{{ node.label }}</span>
    		<span>
    			<el-button type="text" size="mini" @click="append(data)">添加</el-button>
    			<el-button type="text" size="mini" @click="editor(data)">修改</el-button>
    			<el-button type="text" size="mini"	@click="remove(node, data)">删除</el-button>
    		</span>
    	</span>
    </el-tree>
  </div>
</template>
<script>
  export default {
    data(){
      return {
        props: {
        	label: 'name',
        	children: 'children'
        },
        treeData: []
      }
    },
    created() {},
    methods: {
      //添加父节点数据
      appendNode(){},
      //添加子项数据
      append(data){},
      //编辑数据
      editor(data){},
      //移出项目
      remove(node, data){},
      //删除选中的节点
      removeSelected(){}
    }
  }
</script>
<style lang="scss">
.tree-container{ width: 360px; font-size: 12px;
  .top-box{ text-align: right; padding-bottom: 20px; }
}
.custom-tree-node {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: space-between;
	font-size: 14px;
	padding-right: 8px;
}
</style>

此时页面效果如下:

二、模拟数据

在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文件中,代码如下:

<script>
  import DataList from './data'
  export default {
    data(){
      return {
        props: {
        	label: 'name',
        	children: 'children'
        },
        treeData: []
      }
    },
    created() {
      this.loadNode();
    },
    methods: {
	  //加载节点数据
      loadNode(){
        this.treeData = DataList.map(item => item);
      },
      //略...
    }
  }
</script>

如上代码,通过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中,将模拟数据重组,代码如下:

<script>
  import DataList from './data'
  import DGFilterTrees from '@/utils/utils.js'
  export default {
    data(){
      return {
        props: {
        	label: 'name',
        	children: 'children'
        },
        treeData: []
      }
    },
    created() {
      this.loadNode();
    },
    methods: {
	  //加载节点数据
      loadNode(){
        this.treeData = DGFilterTrees(DataList);
      },
      //略...
    }
  }
</script>

此时,所有数据都进行了归类分级显示,页面的效果图如下:

四、选中后显示按钮

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

在span标签上添加v-if,判断node.isCurrent是否为true,代码如下:

<el-tree
	ref="tree"
	:data="treeData"
	:props="props"
	accordion
	show-checkbox
	node-key="id"
	default-expand-all
	:expand-on-click-node="false">
	<span class="custom-tree-node" slot-scope="{ node, data }">
		<span>{{ node.label }}</span>
		<span v-if="node.isCurrent">
			<el-button type="text" size="mini" @click="append(data)">添加</el-button>
			<el-button type="text" size="mini" @click="editor(data)">修改</el-button>
			<el-button type="text" size="mini"	@click="remove(node, data)">删除</el-button>
		</span>
	</span>
</el-tree>

如下图,点击选择”后端基础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()函数,来获取被选中项;然后通过循环,删除每条被选中元素,代码如下:

//移出项目
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();
}

效果如下图:

本期就先介绍到这,添加、修改等功能也比较简单,可以通过element-ui的$prompt弹框控件来实现。

到此这篇关于Element控件Tree实现数据树形结构的示例代码的文章就介绍到这了,更多相关Element Tree树形结构内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 关于vue中路由的跳转和参数传递,参数获取

    关于vue中路由的跳转和参数传递,参数获取

    这篇文章主要介绍了关于vue中路由的跳转和参数传递,参数获取方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • 在vue中使用Echarts利用watch做动态数据渲染操作

    在vue中使用Echarts利用watch做动态数据渲染操作

    这篇文章主要介绍了在vue中使用Echarts利用watch做动态数据渲染操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • vite+vue3+element-plus项目搭建的方法步骤

    vite+vue3+element-plus项目搭建的方法步骤

    因为vue3出了一段时间了,element也出了基于vue3.x版本的element-plus,vite打包听说很快,尝试一下,感兴趣的可以了解一下
    2021-06-06
  • vue使用Echarts绘制地图完整步骤

    vue使用Echarts绘制地图完整步骤

    这篇文章主要给大家介绍了关于vue使用Echarts绘制地图的相关资料,Apache ECharts一个基于JavaScript的开源可视化图表库,提供了常规的折线图、柱状图、散点图、饼图、K线图,用于统计的盒形图,需要的朋友可以参考下
    2023-09-09
  • 如何快速上手Vuex

    如何快速上手Vuex

    本文主要介绍了Javascript中Vuex的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • Vue虚拟Dom到真实Dom的转换

    Vue虚拟Dom到真实Dom的转换

    本文主要介绍了Vue虚拟Dom到真实Dom的转换,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习吧
    2021-07-07
  • vue addRoutes实现动态权限路由菜单的示例

    vue addRoutes实现动态权限路由菜单的示例

    本篇文章主要介绍了vue addRoutes实现动态权限路由菜单的示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-05-05
  • Vue中jsx不完全应用指南小结

    Vue中jsx不完全应用指南小结

    这篇文章主要介绍了Vue中jsx不完全应用指南小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • vue 的 solt 子组件过滤过程解析

    vue 的 solt 子组件过滤过程解析

    这篇文章主要介绍了vue 的 solt 子组件过滤过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-09-09
  • Vue ECharts饼图实现方法详解

    Vue ECharts饼图实现方法详解

    这篇文章主要介绍了在vue.js中,使用echarts组件,创建一个饼图,并且获取饼图的数据和属性,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-12-12

最新评论