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模版语法也是支持递归。
源码中的体现
先找找源码,我们在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 递归组件的资料请关注脚本之家其它相关文章!
相关文章
postcss-pxtorem设置不转换UI框架的CSS单位问题
这篇文章主要介绍了postcss-pxtorem设置不转换UI框架的CSS单位问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-07-07Element-UI el-table对循环产生的空白列赋默认值方式
这篇文章主要介绍了Element-UI el-table对循环产生的空白列赋默认值方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2024-03-03vue parseHTML源码解析hars end comment钩子函数
这篇文章主要为大家介绍了vue parseHTML源码解析hars end comment钩子函数示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-07-07
最新评论