递归和递归组件
递归函数简单的定义是:一个函数调用自身。
递归组件:组件调用自身,即:在组件中调用本组件。
递归组件
递归组件产生的条件
- 结束点:停止递归的情况
- 一组规则:负责将所有的操作减少到结束点
递归组件的用途
用途:树状视图(用于显示文件夹结构),网站上的注释,嵌套菜单等组件等等
如何编写递归组件
刚开始接触递归组件时,觉得好难,苯宝宝搞不定怎么办。第二次接触,决心化繁为简,一步一步实现一个简单的递归组件。
假设,数据只有一层结构,创建一个data1.js
文件,用来保存只有一层的数据
var demoDataSimple = [
{
'id': '1',
'menuName': '基础管理',
'menuCode': '10',
},
{
'id': '2',
'menuName': '商品管理',
'menuCode': ''
},
{
'id': '3',
'menuName': '订单管理',
'menuCode': '30'
},
{
'id': '4',
'menuName': '商家管理',
'menuCode': ''
}
]
export default demoDataSimple
如果要渲染这样一个数据,应该怎么办呢?
- 首先创建一个
demo.vue
组件,将data.js
引入到组件中 - 在组件中使用
v-for
循环将数据展示出来
<template>
<div>
<p>这是一个简单数据结构</p>
<ul>
<li :key="item.id" v-for="item in demoArr">
{{item.menuName}}
</li>
</ul>
</div>
</template>
<script>
import demoDataSimple from './../../static/data1'
export default {
name: 'demo',
data: function () {
return {
demoArr: demoDataSimple
}
}
}
</script>
<style scoped>
</style>
3.将v-for循环的部分抽离出来,放到新的组件Item.vue
中
deom.vue
如下:
<template>
<div>
<p>这是一个简单数据结构</p>
<ul>
<Item :key="item.id" v-for="item in demoArr" :content="item">
</Item>
</ul>
</div>
</template>
<script>
import demoDataSimple from './../../static/data1'
import Item from './Item'
export default {
name: 'demo',
data: function () {
return {
demoArr: demoDataSimple
}
},
components: {
Item
}
}
</script>
<style scoped>
</style>
Item.vue
如下:
<template>
<li v-on:click="test">
{{content.menuName}}
</li>
</template>
<script>
export default {
name: 'Item',
props: ['content'],
methods: {
test: function () {
console.error(this.content)
}
}
}
</script>
<style scoped>
</style>
恭喜你,到这里万里长征已经走出了第一步。。。。
依据现在的代码来看,循环的部分是Item组件,下面开始正式进入递归组件
1.创建一个data.js
文件,用来保存有多层结构的数据,并将其引入到demo.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
2.将上面的Item组件连同他的父组件复制一份,放在下面,将传入的数据变为新的数据
<template>
<div>
<p>这是一个简单数据结构</p>
<ul>
<Item :key='item.id' v-for='item in demoDataSimple' :content='item'>
</Item>
</ul>
<ul>
<Item :key='item.id' v-for='item in demoData' :content='item'>
</Item>
</ul>
</div>
</template>
<script>
import demoDataSimple from './../../static/data1'
import demoData from './../../static/data'
import Item from './Item'
export default {
name: 'demo',
data: function () {
return {
demoDataSimple: demoDataSimple,
demoData: demoData
}
},
components: {
Item
}
}
</script>
<style scoped>
</style>
这时第一层数据仍然能正常展示
3.分析数据结构,如果传到
Item
组件的content
有children属性,就代表它有第二层数据结构,那么,接下来处理第二层数据结构,很显然第二层数据是写在Item
组件中的,改造后的Item
如下:
<template>
<li v-on:click="test">
{{content.menuName}}
<ul v-if="hasChildren">
<Item :key='item.id' v-for='item in content.children' :content='item'>
</Item>
</ul>
</li>
</template>
<script>
export default {
name: 'Item',
props: ['content'],
methods: {
test: function () {
console.error(this.content)
}
},
computed: {
hasChildren: function () {
if (this.content.children && this.content.children.length !== 0) {
return true
} else {
return false
}
}
}
}
</script>
<style scoped>
</style>
运行,发现不止第二层结构出来了,深层的结构也都出来了,惊喜不已,😁😆😁
注意点
- 递归组件必须添加name属性,否则组件自身无法调用自身。
- 在父组件中传值是的prop必须和递归组件中传值的prop相同,在上面的例子中为
content
。
参考文章: