Vue冷门技巧递归组件实践示例详解

作者:JetTsang 时间:2024-05-09 15:13:04 

痛点引出

在平时的开发当中,渲染侧边栏导航菜单有时会遇到过需要侧边栏有多层甚至无限层级的问题。此时更优雅的方式便是使用递归组件

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的一个执行步骤,每个组件创建的时候都会去调用。

Vue冷门技巧递归组件实践示例详解

可以看到如果命中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)
   }
}

来源:https://juejin.cn/post/7206912311562043451

标签:Vue,递归,组件
0
投稿

猜你喜欢

  • MySQL Workbench下载与使用教程详解

    2024-01-13 18:50:26
  • 浅谈python中列表、字符串、字典的常用操作

    2023-02-02 23:59:15
  • 手写一个python迭代器过程详解

    2021-06-29 07:45:23
  • Linux自动备份MySQL数据库脚本代码

    2024-01-24 05:00:12
  • MySQL之主键索引排序失效问题

    2024-01-19 10:38:53
  • 微信小程序创建自定义全局函数以及其调用方法详解

    2023-08-24 20:43:22
  • MySQL 数据库的基础知识

    2024-01-17 03:05:52
  • Python中的logging模块实现日志打印

    2023-07-29 10:51:00
  • Python + opencv对拍照得到的图片进行背景去除的实现方法

    2022-09-06 19:14:51
  • python备份文件以及mysql数据库的脚本代码

    2024-01-21 03:42:01
  • Python读写Json涉及到中文的处理方法

    2021-10-29 10:26:24
  • 详细介绍Python中的set集合

    2023-07-26 07:35:03
  • 使用PyQt4 设置TextEdit背景的方法

    2021-09-01 14:41:43
  • php判断输入不超过mysql的varchar字段的长度范围

    2023-11-14 12:02:10
  • 解析php获取字符串的编码格式的方法(函数)

    2023-10-02 22:26:49
  • PHP7正式版测试,性能惊艳!

    2023-09-12 07:41:43
  • Python标准库06之子进程 (subprocess包) 详解

    2021-05-24 02:00:25
  • Python实现查找二叉搜索树第k大的节点功能示例

    2023-12-17 04:40:09
  • Python 日志管理模块Loguru的用法小结

    2023-02-22 15:45:16
  • window安装mysql(zip、noinstall)

    2009-10-17 21:10:00
  • asp之家 网络编程 m.aspxhome.com