概念:
组件是可以在它们自己的模板中调用自身的。不过它们只能通过 name 选项来做这件事。
之前在写组件时总有些疑惑,为什么export default导出的对象中有个name属性,今天看过递归组件之后,才发现这个name属性的一个比较重要的作用。(当然。name属性的还有其他的用处)。
用法:
1、首先我们要知道,既然是递归组件,那么一定要有一个结束的条件,否则就会使用组件循环引用,最终出现“max stack size exceeded”的错误,也就是栈溢出。那么,我们可以使用v-if="false"作为递归组件的结束条件。当遇到v-if为false时,组件将不会再进行渲染。
既然要用递归组件,那么对我们的数据格式肯定是需要满足递归的条件的。就像下边这样,这是一个树状的递归数据。
1 [ 2 { 3 "name": "黄焖鸡米饭111111111", 4 cList: [ 5 { "name": "二级黄焖鸡" }, 6 { 7 "name": "one chicken", 8 cList: [{ "name": ‘三级黄焖鸡3333‘, cList: [{ "name": "四级黄焖鸡" }] }] 9 } 10 ] 11 }, 12 { "name": "2222222222" }, 13 { 14 "name": "黄焖鸡米饭33333333", cList: [ 15 { "name": "二级黄焖鸡" }, 16 { "name": "one chicken" } 17 ] 18 }, 19 ]
接下来,我们就用这个树状数据,做一个简单版的树状菜单。树状菜单,也是递归组件最常用的方法之一。
首先,我们先创建一个tree组件,这个组件作为使用递归组件的父组件,我们来看下具体写法
1 <template> 2 <div> 3 <my-trees :list="list"></my-trees> 4 </div> 5 </template> 6 <script> 7 import myTrees from ‘./treeMenus‘ 8 export default { 9 components: { 10 myTrees 11 }, 12 data () { 13 return { 14 list: [ 15 { 16 name: ‘黄焖鸡米饭111111111‘, 17 cList: [ 18 { name: ‘二级黄焖鸡‘ }, 19 { 20 name: ‘one chicken‘, 21 cList: [ 22 { name: ‘三级黄焖鸡3333‘, cList: [{ name: ‘四级黄焖鸡‘ }] } 23 ] 24 } 25 ] 26 }, 27 { name: ‘2222222222‘ }, 28 { 29 name: ‘黄焖鸡米饭33333333‘, 30 cList: [{ name: ‘二级黄焖鸡‘ }, { name: ‘one chicken‘ }] 31 } 32 ] 33 } 34 }, 35 methods: {} 36 37 } 38 </script>
ok,可以看到,<my-trees />就是我们说的递归组件,当使用它时,只需要把上边我们定义好的数据通过props的方式传进去即可。
接下来,递归组件接收到了父组件传递的数据,就可以进行递归啦,我们来看下边的实现:
1 <template> 2 <ul> 3 <li v-for="(item,index) in list " :key="index"> 4 <p>{{item.name}}</p> 5 <tree-menus :list="item.cList"></tree-menus> 6 </li> 7 </ul> 8 </template> 9 <style> 10 ul{ 11 padding-left: 20px!important; 12 } 13 </style> 14 <script> 15 export default{ 16 name:‘treeMenus‘, 17 props:{ 18 list: Array 19 } 20 } 21 </script>
注意本文开头所说,name属性的使用(你可以把它当作从import导入了一个组件并注册,我们在temlpate可以使用<tree-menus></tree-menus>使用子组件自身进行递归了)
总结:
通过props从父组件拿到数据,递归组件每次进行递归的时候都会tree-menus组件传递下一级cList数据,(大家可以想象一下整个过程),整个过程结束之后,递归也就完成了,当然,这段代码只是简单的做了下递归组件的使用。对于折叠树状菜单来说,我们一般只会去渲染一级的数据,当点击一级菜单时,再去渲染一级菜单下的结构,如此往复。那么v-if就可以实现我们的这个需求,当v-if设置为false时,递归组件将不会再进行渲染,设置为true时,继续渲染。
最后也为大家准备了一个树状折叠菜单的递归组件实现方式,没有样式大家不要介意啦~
1 <template> 2 3 <ul> 4 <li v-for="(item,index) in list" :key="index"> 5 <p @click="changeStatus(index)">{{item.name}}</p> 6 <tree-menus v-if="scopesDefault[index]" :list="item.cList"></tree-menus> 7 </li> 8 </ul> 9 10 </template> 11 <style> 12 ul { 13 margin-top: 50px; 14 padding-left: 20px !important; 15 } 16 </style> 17 <script> 18 // import treeMenus from ‘./treeMenu2.vue‘ 19 export default { 20 name: ‘treeMenus‘, 21 props: { 22 list: Array 23 }, 24 data() { 25 return { 26 scopesDefault: [], 27 scopes: [] 28 } 29 }, 30 31 methods: { 32 changeStatus(index) { 33 console.log(index); 34 if (this.scopesDefault[index] == true) { 35 this.$set(this.scopesDefault, index, false) 36 } else { 37 this.$set(this.scopesDefault, index, this.scopes[index]) 38 } 39 }, 40 scope() { 41 this.list.forEach((item, index) => { 42 this.scopesDefault[index] = false 43 if (‘cList‘ in item) { 44 this.scopes[index] = true 45 console.log(item, index) 46 } else { 47 this.scopes[index] = false 48 } 49 }) 50 console.log(this.scopesDefault) 51 } 52 }, 53 created() { 54 this.scope() 55 } 56 } 57 </script>
原文:https://www.cnblogs.com/hecheng123/p/12099315.html