一个可递归遍历的 Vue 树型组件
发布于: 2021 年 04 月 13 日

序
在创建列表时,常常会遇到一层套一层,如同套娃一般的列表结构。这样的列表结构其实对于我来说还是挺麻烦的,经常需要一层层的写。(一般而言的结构三层应该是最多了,但是遇到特殊情况可能就不止了)
那么遇到列表不同层的数据结构类似的情况,是不是可以使用递归的方法来创建一个组件呢。
接下来做一下尝试:需要变成列表的数据
options: [ { value: 1, label: '东南', children: [{ value: 2, label: '上海', children: [ { value: 3, label: '普陀' }, { value: 4, label: '黄埔' }, { value: 5, label: '徐汇' } ] }, { value: 7, label: '江苏', children: [ { value: 8, label: '南京' }, { value: 9, label: '苏州' }, { value: 10, label: '无锡' } ] }, { value: 12, label: '浙江', children: [ { value: 13, label: '杭州' }, { value: 14, label: '宁波' }, { value: 15, label: '嘉兴' } ] }] }, { value: 17, label: '西北', children: [{ value: 18, label: '陕西', children: [ { value: 19, label: '西安', children: [{ value: 19, label: '陕西', children: [ { value: 30, label: '西安' }, { value: 40, label: '延安' } ] }, { value: 41, label: '新疆维吾尔族自治区', children: [ { value: 42, label: '乌鲁木齐' }, { value: 43, label: '克拉玛依' } ] }] }, { value: 20, label: '延安' } ] }, { value: 21, label: '新疆维吾尔族自治区', children: [ { value: 22, label: '乌鲁木齐' }, { value: 23, label: '克拉玛依' } ] }] }]复制代码
效果
递归实现的列表
分析
从数据开始着手分析,在这份数据当中,层级较多,但是每一层中的对象都有自身的 value 值和 label 值,以及可能存在的 children 子层级数组对象。
可以先创建一个组件 treeVue,treeVue 组件通过 props 获取到父组件传递过来的列表数据。
通过分析每一层的各个元素,使用 $set 给元素添加一个 showflag 属性,这个属性控制其子层级的显隐
var treeVue = { name:'treevue', template: "#treevue", props: ['datavalue'], data: function() { return { options:'', //获取到的数据 } }, mounted: function() { var self = this; this.options = this.datavalue; $.each(this.options,function(index,item){ self.$set(item, 'showflag', true) }) }, watch: {}, methods: {
}, filters:{ textshow:function(str,flag){ if(flag) { if(str) return " -- 显示"; else return " -- 隐藏"; } else { return "" } } }}复制代码
在 HTML 中 treeVue 组件
<div class="tree-vue" > <div class="treefirst" v-for="(item1,index1) in datavalue" :key='index1' > <div class="btn_name" @click.stop="item1.showflag = !item1.showflag"> {{ item1.label }}{{ item1.showflag | textshow(item1.children) }} </div> </div></div>复制代码
如以上这种方式使用 treevue 组件,只能显示第一层的元素
所以需要在调用的组件中再添加一句<treevue v-show="item1.children && item1.showflag" :datavalue="item1.children" ></treevue>
这样才能够使得组件进行递归
<div class="tree-vue" > <div class="treefirst" v-for="(item1,index1) in datavalue" :key='index1' > <div class="btn_name" @click.stop="item1.showflag = !item1.showflag"> {{ item1.label }}{{ item1.showflag | textshow(item1.children) }} </div> <treevue v-show="item1.children && item1.showflag" :datavalue="item1.children" ></treevue> </div></div>复制代码
完整代码
<!DOCTYPE html><html> <head> <meta charset="utf-8"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js" type="text/javascript" charset="utf-8"></script> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.0/jquery.min.js" type="text/javascript" charset="utf-8"></script> <title>vue树型组件</title> <style type="text/css"> .treefirst{ margin-left: 30px; } .treefirst .btn_name { display: inline-block; cursor: pointer; background-color: #1CD8F3; } .treefirst .treefirst .btn_name{ background-color: yellow; } .treefirst .treefirst .treefirst .btn_name{ background-color: greenyellow; } .treefirst .treefirst .treefirst .treefirst .btn_name{ background-color: peachpuff; } .treefirst .treefirst .treefirst .treefirst .treefirst .btn_name{ background-color: pink; } </style> </head> <body> <div id="app"> <treevue :datavalue="options" ></treevue> </div> <!-- 树型图组件 --> <script id="treevue" type="text/template"> <div class="tree-vue" > <div class="treefirst" v-for="(item1,index1) in datavalue" :key='index1' > <div class="btn_name" @click.stop="item1.showflag = !item1.showflag"> {{ item1.label }}{{ item1.showflag | textshow(item1.children) }} </div> <treevue v-show="item1.children && item1.showflag" :datavalue="item1.children" ></treevue> </div> </div> </script> <script type="text/javascript"> var treeVue = { name:'treevue', template: "#treevue", props: ['datavalue'], data: function() { return { options:'', //获取到的数据 } }, mounted: function() { var self = this; this.options = this.datavalue; $.each(this.options,function(index,item){ self.$set(item, 'showflag', true) }) }, watch: {}, methods: { }, filters:{ textshow:function(str,flag){ if(flag) { if(str) return " -- 显示"; else return " -- 隐藏"; } else { return "" } } } } var vm = new Vue({ el:'#app', data:{ options: [ { value: 1, label: '东南', children: [{ value: 2, label: '上海', children: [ { value: 3, label: '普陀' }, { value: 4, label: '黄埔' }, { value: 5, label: '徐汇' } ] }, { value: 7, label: '江苏', children: [ { value: 8, label: '南京' }, { value: 9, label: '苏州' }, { value: 10, label: '无锡' } ] }, { value: 12, label: '浙江', children: [ { value: 13, label: '杭州' }, { value: 14, label: '宁波' }, { value: 15, label: '嘉兴' } ] }] }, { value: 17, label: '西北', children: [{ value: 18, label: '陕西', children: [ { value: 19, label: '西安', children: [{ value: 19, label: '陕西', children: [ { value: 30, label: '西安' }, { value: 40, label: '延安' } ] }, { value: 41, label: '新疆维吾尔族自治区', children: [ { value: 42, label: '乌鲁木齐' }, { value: 43, label: '克拉玛依' } ] }] }, { value: 20, label: '延安' } ] }, { value: 21, label: '新疆维吾尔族自治区', children: [ { value: 22, label: '乌鲁木齐' }, { value: 23, label: '克拉玛依' } ] }] }] }, methods:{}, components: { treevue: treeVue } }) </script> </body></html>
复制代码
划线
评论
复制
发布于: 2021 年 04 月 13 日阅读数: 142
版权声明: 本文为 InfoQ 作者【空城机】的原创文章。
原文链接:【http://xie.infoq.cn/article/dce8ea8c4bf568759ff50cf58】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
空城机
关注
曾经沧海难为水,只是当时已惘然 2021.03.22 加入
业余作者,在线水文 主要干前端的活,业余会学学python 欢迎各位关注,互相学习,互相进步











评论