视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue递归实现树形菜单方法实例
2020-11-27 22:04:14 责编:小采
文档


什么是树形菜单还是要简单的啰嗦一下,比如:


上图是截图自elementui的实例,实现方式是用文档结构(类似像原生Dom文档结构的写法)的方式,好处就是很灵活,可以方便的自定义,作为一个通用视图组件库这是正确的做法。

在实际的企业应用中,菜单要比这复杂很多,层次也要多很多,如果我们采取手动编写文档结构的方式,会导致代码亢长,阅读和维护都很低效。毫无疑问所有Vuer都会想到用一个数据结构来驱动文档结构。vue-router的数据结构恰恰就是完美的嵌套层次结构(树结构),同时vue文档中也提到了递归组件,基于这两点,我们来撸码,不过这次有所不同,我们选择使用render函数来实现,而不是在模板中递归。

数据结构:vue-router的数据结构

const routes = [
 {
 name: 'home',
 path: '/home',
 meta: { text: '首页' }
 },
 {
 name: 'inner',
 path: '/inner',
 meta: { text: '内部平台' },
 children: [
 {
 name: 'oa',
 path: 'oa',
 meta: { text: 'OA' }
 },
 {
 name: 'jira',
 path: 'jira',
 meta: { text: 'Jira' }
 },
 {
 name: 'wiki',
 path: 'wiki',
 meta: { text: 'Wiki' }
 },
 {
 name: 'caiwu',
 path: 'caiwu',
 meta: { text: '财务' },
 children: [
 {
 name: 'chailv',
 path: 'chailv',
 meta: { text: '差旅' }
 },
 {
 name: 'richang',
 path: 'richang',
 meta: { text: '日常' },
 children: [
 {
 name: 'taxi',
 path: 'taxi',
 meta: { text: '交通' }
 },
 {
 name: 'tel',
 path: 'tel',
 meta: { text: '通信' }
 }
 ]
 }
 ]
 }
 ]
 },
 {
 name: 'sec',
 path: '/sec',
 meta: { text: '审核' },
 children: [
 {
 name: 'acl',
 path: '/acl',
 meta: { text: 'ACL' }
 }
 ]
 }
]

组件实现:

先看看render函数,其中包含一个递归函数elements:

render (r) {
 return r(
 'el-menu',
 {
 props: {
 backgroundColor: "#545c",
 textColor: "#fff",
 activeTextColor: "#ffd04b"
 },
 on: {
 select: this.onSelect
 }
 },
 this.elements(this.routes, r)
 )
 }

elements函数:

elements (routes, r) {
 return routes
 .map(route => {
 if (!route.paths) route.paths = []
 if (route.children && route.children.length) {
 return r(
 'el-submenu',
 {
 props: {
 index: route.name
 }
 },
 [
 r(
 'span',
 {
 slot: 'title'
 },
 [
 route.meta.text
 ]
 ),
 this.elements(route.children, r)
 ]
 )
 } else if (route.path) {
 return r(
 'el-menu-item',
 {
 props: {
 index: route.name
 }
 },
 [
 route.meta.text
 ]
 )
 } else {
 return null
 }
 })
 .filter(item => item)
 }

最终效果:


完整代码示例请戳:https://codepen.io/360vislab/pen/GQqBve

总结:

下载本文
显示全文
专题