Vue冷门技巧递归组件实践示例详解
痛点引出
在平时的开发当中,渲染侧边栏导航菜单有时会遇到过需要侧边栏有多层甚至无限层级的问题。此时更优雅的方式便是使用递归组件
<el-menu>
<template slot="title">
<i class="el-icon-location"></i>
<span>菜单</span>
</template>
<el-submenu index="1-1">
<template slot="title">子菜单</template>
<el-menu-item index="1-1-1">子菜单选项1</el-menu-item>
<el-submenu index="1-1-2">
<template slot="title">子菜单的子菜单</template>
<el-menu-item index="1-1-2-1">子菜单的子菜单的选项1</el-menu-item>
</el-submenu>
</el-submenu>
</el-submenu>
</el-menu>
可以看到这部分重复的代码可以完全抽离出来做单独的组件。
<el-submenu>
<el-menu-item></el-menu-item>
...
</el-submenu>
那么问题来了,在一层当中又有重复的submenu怎么办?显然这个层级是需要动态生成的。比如:
<el-submenu>
<el-menu-item></el-menu-item>
...
<el-submenu>
<el-menu-item></el-menu-item>
...
<el-submenu>
<el-menu-item></el-menu-item>
...
//这里省略很多很多层
</el-submenu>
</el-submenu>
</el-submenu>
很明显,这里需要可以用递归(recursive) 的思想来解决, 那么在template模版当中有办法做这样的组件吗?答案当然是可以,template模版语法也是支持递归。
源码中的体现
先找找源码,我们在class="lazy" data-src/core/global-api.ts当中找到initExtend函数,这个函数是initGlobalAPI的一个执行步骤,每个组件创建的时候都会去调用。
可以看到如果命中name,则会给自己的components的配置项当中注册自己,使得可以在编译的时候可以识别到自己,从而在template模版语法当中去使用。
组件示例封装
首先定义数据结构能描述这样的菜单
[
{
id: '1',
title: '父菜单',
children:[
{id:'1-1',title:'子选项',children:[]},
{id:'1-1',title:'子菜单',children:[
{id:...,title:...,children:...},
...
]},
...
]
}
]
简单点描述就是
interface item:{
id: string,
title: string,
children: item[] | []
}
item[]
然后开始封装组件
// RescursiveMenu.vue
<template>
<el-submenu :index="menuItem.id" v-if="menuItem.children.length">
<template slot="title">{{ menuItem.title }}</template>
<template v-for="item in menuItem.children">
<RecursiveMenu :menuItem="item"/>
</template>
</el-submenu>
<el-menu-item v-else>{{ menuItem.title }}</el-menu-item>
</template>
<script>
export default {
name:"RecursiveMenu",
props: {
menuItem: Object
}
}
</script>
当然这只是简单示例demo,后续根据业务需求相信难不倒各位看官。
使用:
<el-submenu>
<template v-for="item in menuList.children">
<RecursiveMenu :menuItem="item" :key="item.id"/>
</template>
</el-submenu>
小扩展
同样的,vue也支持jsx/tsx语法 ,使用jsx则需要抽象需要重复的过程,封装成渲染函数来实现递归,这里采用整个数组渲染过程抽象重复,来实现递归。
//MyMenu.jsx
export default {
name:"RecursiveMenu",
props: {
menuList: Array,
dafault:()=>([])
},
render(){
const recursiveRender = (menuList)=>{
return menuList.map((menuItem)=>{
return menuItem.children.length > 0 ? (
<elSubmenu index="{menuItem.id}">
<div slot="title">{menuItem.title}</div>
{recursiveRender(menuItem.children)}
</elSubmenu>
):(
<elMenuItem key="{menuItem.id}">{ menuItem.title }</elMenuItem>
)
}
)
}
return (<elMenu>
{recursiveRender(this.menuList)}
</elMenu>
)
}
}
当然,如果想用jsx复刻上诉template当中抽象的逻辑,可以写成这样:
// RecursiveMenu.jsx
export default {
name:"RecursiveMenu",
props: {
menuItem: Object,
dafault:()=>({})
},
render(){
const recursiveRender = (menuItem)=>{
return menuItem.children.length > 0 ? (
<elSubmenu index="{menuItem.id}">
<div slot="title">{menuItem.title}</div>
{menuItem.children.map(children=>recursiveRender(children))}
</elSubmenu>
):(
<elMenuItem key="{menuItem.id}">{ menuItem.title }</elMenuItem>
)
}
return recursiveRender(this.menuItem)
}
}
总结
Vue当中实现递归渲染,可以使用模版语法和jsx语法。而实现本质上是抽象出重复的逻辑,以及找到递归退出点。
以上就是Vue冷门技巧递归组件实践示例详解的详细内容,更多关于Vue 递归组件的资料请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341