背景
1、个人心血来潮想试试如何实现无限嵌套组件,也就是当数据不确定的情况下,如何渲染组件
2、自我思考以后肯定会需要用到这种思维和开发方式,早点学,早点掌握
3、好奇之前jqui的文件夹列表实现
说明:
组件写的很垃圾,很丑,大家请关注原理实现
开始实现
第一步思考
首先既然是树形渲染,那么for循环是肯定需要的,
问题:
for循环的时候只能单列循环,也确实是数据驱动,但是当数据是层层嵌套该怎么办呢?两个for循环?但是想想也不现实啊
第二步思考
通过百度得知,所有无限嵌套都是利用了递归算法
那vue如何实现呢?我最后从vuejs官方得到了这段话
组件在渲染树中互为对方的后代和祖先 地址:https://cn.vuejs.org/v2/guide/components-edge-cases.html#递归组件
具体我就不多说了,vue的官方例子有说明原理也讲述清楚了,只是没有完整的实例,那么下面就是自己来实现这个实例了
第三步实现
数据一次
首先你的数据一开始是这样的
menus2: [
{
text: "水果1"
},
{
text: "苹果1"
},
{
text: "橘子1"
}
]
那么我就先for循环出第一组数据得到
数据二次
现在后端说我的菜单会多一层数据,数据变成这样的
menus2: [
{
text: "水果1",
children: [
{
text: "香蕉2"
}
]
},
{
text: "苹果1",
children: [
{
text: "木瓜2"
}
]
},
{
text: "橘子1",
children: [
{
text: "百香2"
}
]
}
]
实现也是很简单,我可以for循环一次,再内嵌一次就ok了,但是记住vue官方的话,递归组件在于组件相互调用互为父子关系,
那么我就写一个专门循环子数据的组件,然后放进来
外层for循环代码:
<ul>
<li v-for="(item, index) in menus2" :key="index">
<div class="one">
{{ item.text }}
</div>
<div v-if="item.children && item.children.length > 0">
<tree-ul :node="item.children"></tree-ul>
</div>
</li>
</ul>
内部子组件代码,去循环数据的二层结构
<div class="twoli">
<template v-for="(item, index) in node">
<div class="two" :key="index">{{ item.text }}</div>
<template v-if="item.children && item.children.length > 0">
<tree-li :key="index" :node="item.children"></tree-li>
</template>
</template>
</div>
注意代码结构,其实是一个单纯的for循环,这样我就得到了得到了二层循环数据
页面效果
第三次数据变化
数据:
menus2: [
{
text: "水果1",
children: [
{
text: "香蕉2",
children: [
{
text: "芒果3"
}
]
}
]
},
{
text: "苹果1",
children: [
{
text: "木瓜2",
children: [
{
text: "芒果3"
}
]
}
]
},
{
text: "橘子1",
children: [
{
text: "百香2",
children: [
{
text: "芒果3"
}
]
}
]
}
]
可以看到数据变成了三层结构
一样,按上一次的原理,我再写一个组件去循环第三层数据
<div class="sanli">
<template v-for="(item, index) in node">
<div class="san" :key="index">{{ item.text }}</div>
<template v-if="item.children && item.children.length > 0">
<tree-ul :key="index" :node="item.children"></tree-ul>
</template>
</template>
</div>
这时候效果
可以看到都已经循环出来了
第四次数据变化
数结构
menus2: [
{
text: "水果1",
children: [
{
text: "香蕉2",
children: [
{
text: "芒果3",
children: [
{
text: "李子4"
}
]
}
]
}
]
},
{
text: "苹果1",
children: [
{
text: "木瓜2",
children: [
{
text: "芒果3"
}
]
}
]
},
{
text: "橘子1",
children: [
{
text: "百香2",
children: [
{
text: "芒果3"
}
]
}
]
}
]
这时候看到数据已经到了第四层,其实我上面的代码已经把互相嵌套的部分写完了
回顾两次内部组件代码
组件名称分别是:
tree-ul,tree-li
我上面贴代码的时候其实偷懒了,把后面的代码提前写好了
tree-ul代码调用了tree-li组件去循环上层传递过来的数据,然后如果发现有子层级,则传递给tree-li组件
<div class="twoli">
<template v-for="(item, index) in node">
<div class="two" :key="index">{{ item.text }}</div>
<template v-if="item.children && item.children.length > 0">
<tree-li :key="index" :node="item.children"></tree-li>
</template>
</template>
</div>
tree-li代码获取上层传递过来的数据,如果发生子层级,传递给tree-ul组件
<div class="sanli">
<template v-for="(item, index) in node">
<div class="san" :key="index">{{ item.text }}</div>
<template v-if="item.children && item.children.length > 0">
<tree-ul :key="index" :node="item.children"></tree-ul>
</template>
</template>
</div>
最后大家发现,两个组件之间代码基本上一模一样,但是主要是互相调用了一遍。因为vue组件不可能自己调用自己,那么可以用这样的方式实现递归调用,
递归算法原理:自己调用自己
然后讲一下vue官方注意的地方,两个组件注册不能用同步注册方式,
必须是全局注册,或者内部异步注册
我这里是这样的内部注册方式
components: { treeUl: () => { return import("./tree.vue"); } }
最后效果图,第四层级也出来了
我再加一层数据,有五层
再加那么再有,我可以无限的子嵌套下去。
数据部分:
menus2: [
{
text: "水果1",
children: [
{
text: "香蕉2",
children: [
{
text: "芒果3",
children: [
{
text: "李子4",
children: [
{
text: "葡萄5"
}
]
}
]
}
]
}
]
},
{
text: "苹果1",
children: [
{
text: "木瓜2",
children: [
{
text: "芒果3"
}
]
}
]
},
{
text: "橘子1",
children: [
{
text: "百香2",
children: [
{
text: "芒果3"
}
]
}
]
}
]