vue 递归组件
前言
对于一些有规律的 dom 结构,我们可以通过递归方式来生成这个结构,,那么在 vue 的模板中,我们能不能递归生成dom,答案是肯定的,在 vue 的组件中能够调用自己本身。
开始简单demo
准备数据
首先为了使用递归组件需要准备一份数据,因为这次是生成一个菜单,所以准备一个菜单书数据,新建一个testdata.js 文件代码如下
var demoData = [
{
'id': '1',
'menuName': '基础管理',
'menuCode': '10',
'children': [
{
'menuName': '用户管理',
'menuCode': '11'
},
{
'menuName': '角色管理',
'menuCode': '12',
'children': [
{
'menuName': '管理员',
'menuCode': '121'
},
{
'menuName': 'CEO',
'menuCode': '122'
},
{
'menuName': 'CFO',
'menuCode': '123'
},
{
'menuName': 'COO',
'menuCode': '124'
},
{
'menuName': '普通人',
'menuCode': '124'
}
]
},
{
'menuName': '权限管理',
'menuCode': '13'
}
]
},
{
'id': '2',
'menuName': '商品管理',
'menuCode': ''
},
{
'id': '3',
'menuName': '订单管理',
'menuCode': '30',
'children': [
{
'menuName': '订单列表',
'menuCode': '31'
},
{
'menuName': '退货列表',
'menuCode': '32',
'children': []
}
]
},
{
'id': '4',
'menuName': '商家管理',
'menuCode': '',
'children': []
}
];
export default demoData;
这是使用时 ES6 语法,导出一个数据,所以这里必须注意 ES6 导出的语法,如果不清楚 ES6 的语法自行了解.
建立树形组件
现在建立树形组件,首先新建一个文件treeMenu,代码如下
<template>
<li>
<span @click="toggle">
<i v-if="hasChild" class="icon" v-bind:class="[open ? 'folder-open': 'folder' ]"></i>
<i v-if="!hasChild" class="icon file-text"></i>
{{model.menuName}}
</span>
<ul v-show="open" v-if="hasChild">
<tree-menu v-for="(item,index) in model.children" v-bind:model="item" v-bind:key="index"></tree-menu>
</ul>
</li>
</template>
<script>
export default {
name: "treeMenu",
props: ['model'],
data(){
return {
open:false
}
},
computed:{
hasChild(){
return this.model.children && this.model.children.length
}
},
methods:{
toggle(){
if(this.hasChild){
this.open = !this.open
}
}
}
}
</script>
<style>
ul {
list-style: none;
margin: 10px 0;
}
li {
padding: 3px 0;
}
li > span {
cursor: pointer;
font-size: 14px;
line-height: 20px;
}
i.icon {
display: inline-block;
width: 20px;
height: 20px;
margin-right: 5px;
background-repeat: no-repeat;
vertical-align: middle;
}
.icon.folder {
background-image: url(/src/assets/folder.png);
}
.icon.folder-open {
background-image: url(/src/assets/folder-open.png);
}
.icon.file-text {
background-image: url(/src/assets/file-text.png);
}
.tree-menu li {
line-height: 1.5;
}
</style>
上述代码中我们需要注意,这个组件必须含有 name 这个属性,因为没有 name 这个属性会造成控件自身不能调用自身,自身调用的时候最好有绑定 key ,因为这个 key 是唯一的标识,对于 vue 更新控件比较好.除非控件非常简单就不用 key.
另外一个需要注意就是递归组件时候,需要有一个条件来终止递归,在这里使用 v-for 隐形条件终止递归. props 这个属性其实主要传递父控件的数据的参数,具体用法可以参详 vue 的官方文档.
sidebar 控件
新建一个 sidebar 控件,代码如下
<template>
<div class="tree-menu">
<ul v-for="menuItem in theModel">
<my-tree :model="menuItem"></my-tree>
</ul>
</div>
</template>
<script>
import testData from './testdata';
import myTree from './treeMenu';
export default {
name: "side-bar",
components: {
myTree
},
data() {
return {
theModel: testData
}
}
}
</script>
在把该 sidebar 组件添加到 HelloWorld.vue 中,成功后如下图:
成功后会出现如下图的