最近做项目经常会用到一些UI库,比如element
、iview
等,这些能够快速构建应用的库真的十分方便。比如iview
的级联菜单很是好用,但是在使用的同时不免起了一些疑惑,它是怎么做到多级联动,依我所知,如果一个数据是多层的,我们就要多次使用v-for
,并且需要知道要循环几次,但是这个组件貌似不需要多次复用。好啦,下面进入正题!
数据
首先我们手里是一份这样的JSON
数据:
list: [
{
"id": "1",
"menuName": "项目管理",
"childTree": [{
"menuName": "项目进度",
"childTree": [{
"menuName": "项目一",
"childTree": [{ "menuName": "详细信息" }]
}]
}, {
"menuName": "任务安排"
}]
},
{
"id": "2",
"menuName": "数据统计"
},
{
"id": "3",
"menuName": "人员管理"
}]
子组件递归
这是最重要的环节,组件的递归实现了级联菜单的多级联动,这个过程就如同实现对象的深复制一样。那么接下来我们按照这份数据写一个递归组件:
// 子组件代码
<template>
<li>
<span @click="toggle">
{{ model.menuName }}
</span>
<ul v-if="isFolder" v-show="open">
<items v-for="(item, index) in model.childTree" :model="item" :key="index"></items>
</ul>
</li>
</template>
<script type="text/javascript">
export default {
// 组件递归必要条件,name属性
name: 'items',
props: ['model'],
data() {
return {
// 控制子列表的显示隐藏
open: false
}
},
computed: {
// 是否还有子列表需要渲染,作为v-if的判断条件
isFolder() {
return this.model.childTree && this.model.childTree.length
}
},
methods: {
// 切换列表显示隐藏的方法
toggle() {
if(this.isFolder) {
this.open = !this.open
}
},
}
}
</script>
这里要强调以下,组件的name
属性必须要有,否则无法实现递归,当然递归也需要有终止的条件,上边的isFloder
便是了。
父组件调用
<template>
<div>
<ul>
<items v-for="(model, index) in list" :model="model" :key="index"></items>
</ul>
</div>
</template>
<script type="text/javascript">
components: {
Items
},
data() {
return {
list: ...
}
}
</script>
这里也有需要注意的,v-for
循环需要绑定key
,否则会报警告。
最后来看下这个简单级联菜单的效果: