您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > javascript

JS函数式编程和递归探索:路由树的操作

时间:2022-03-16 10:58:44  来源:  作者:前端梁哥

开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vue-router,KeepAlive组件有一点了解。现在,我们开始吧。

熟悉element-ui的童鞋们都知道,ElMenuItem和ElSubMenu都需要一个index属性,该属性必须是唯一的。现在,我们想把路由配置直接应用于ElMenu,该如何确保index的唯一性呢?我们需要有一个生成唯一index的函数。如下是genKey函数的定义,是不是很简单?

export const genKey = ((k = 1) => () => k++)()

现在,我们创建addRouteMetaKey函数,该函数对路由树进行递归遍历,为每一个路由配置的meta属性动态添加key字段。这个函数很简单,属于最基础的递归使用例子,我就不做太多解释了。

提示:数组的forEach方法不是纯函数,因为它有副作用,所以forEach方法不能称之为函数式编程工具。

/** @param {import('vue-router').RouteRecordRaw[]} routes */
const addRouteMetaKey = routes => {
  routes.forEach(route => {
    if (route.meta) {
      route.meta.key = genKey()
    } else {
      route.meta = { key: genKey() }
    }
    route.children && addRouteMetaKey(route.children)
  })
  return routes
}

通过addRouteMetaKey函数,我们可以把路由的meta.key作为index的值了。

现在,我们想实现另一个功能,就是基于标签页的路由组件缓存控制。使用过Vuejs KeepAlive组件的童鞋们,应该多多少少都遇到一些坑吧?在我们的项目中,有一个顶部标签页导航,每个tab项对应一个url,以每个url对应路由的title作为tab项标题,当切换tab的时候加载缓存中的url对应的路由组件,关闭tab项,下次打开该路由url,重新挂载对应的路由组件,而不是从缓存中加载。

当路由层级不确定的时候,KeepAlive会变的难以手动控制。所以,我剑走偏锋,尝试了一种简单的解决方案,实践证明:这是非常有效的。我的方案就是把无限层级的路由树转化为一维数组。通过为meta添加必要的字段,进行页面结构个性化定制。

我们需要把每层路由配置的path转化为全路径,所以需要一个函数:getRouteFullPath,该函数定义如下:

/**
 * 获取路由全路径
 * @description 如果path以 / 开头(属于绝对路径),则直接返回,否则拼接路径
 * @param {string} path
 * @param {string} parentPath
 */
export const getRouteFullPath = (path, parentPath) => {
  return !parentPath || path.startsWith('/') ? path : joinPath(parentPath, path)
}

getRouteFullPath函数中使用到的joinPath函数用于将多个路径字符串拼接为1个完整的路径,定义如下:

/** @param {string[]} paths */
export const joinPath = (...paths) => {
  const j = '/'
  const [a, ...b] = paths
  return (a.endsWith('/') ? a.replace(/(/+)$/gm, j) : a + j) + b.map(_ => _.replace(/^(/+)|(/+)$/gm, '')).join(j)
}

现在,我们把路由树转化为一维数组。我们定义toFlatRoutes函数,该函数使用了数组的reduce方法对路由树进行聚合递归,将路由配置中的path属性的值替换为全路径,还顺便给路由配置添加了name属性,返回一个新的一维路由配置数组。这是函数式编程和递归结合的一个例子。

/**
 * @param {import('vue-router').RouteRecordRaw[]} routes
 * @returns {import('vue-router').RouteRecordRaw[]}
*/
const toFlatRoutes = (routes, parentPath) => {
  return routes.reduce((t, r) => {
    const path = getRouteFullPath(r.path, parentPath)
    return [
      ...t,
      ...(r.children
          ? toFlatRoutes(r.children, path)
          : [{ ...r, path, name: r.name || `name-${genKey()}` }]
        )
    ]
  }, [])
}

以上,我们解决了KeepAlive的缓存控制问题;现在,我们又有了一个新的用户体验上的需求,就是我们想根据url对应的路由,自动展开该路由meta.key所属的侧边菜单;我们通过查阅element-ui文档得知,ElMenu有一个open方法,接收index作为参数,展开index对应的菜单。

现在的问题是,我们的路由对应的index是ElMenuItem的,而路由树已经被我们转化为了一维数组,通过路由的matched字段是得不到我们想要的菜单index的。所以,我们需要遍历原始路由树

如下代码,我们定义getMenuKey函数,该函数接收的参数为route对象。如果路由存在,我们进行查找。首先进行简单查找,如果找到一个菜单menu,则返回该菜单的meta.key;如果简单查找无果,则对路由树进行递归查找;这是函数式编程和递归结合的另一个例子。

/**
 * @param {import('vue-router').RouteRecordRaw} item
 * @returns {number|undefined}
*/
export const getMenuKey = item => {
  if (item) {
    const menu = state.menus.find(m => item.path.startsWith(m.path))
    if (menu) {
      return menu.meta.key
    }
    const itemKey = item.meta.key
    return (function findFunc (menus) {
      /** @param {import('vue-router').RouteRecordRaw} m */
      const fn = m => m.meta.key === itemKey ? true : m.children && m.children.some(fn)
      const curMenu = menus.find(fn)
      return curMenu && curMenu.meta.key
    })(state.menus) // state是响应式对象,定义:const state = reactive({ menus: [] })
  }
}

现在,我们大功告成了;以上就是本节的知识点,童鞋们理解了吗?只要我们熟悉递归的使用,其实操作树很简单。如果大家还有不懂的,可以评论区问我。感谢阅读!



Tags:JS函数   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
JS函数式编程和递归探索:路由树的操作
开始切入正题之前,有必要告知大家一下,这篇文章可能有一些深度,初学者可能理解会有些吃力。我会尽量把复杂问题简单化,争取让每个阅读的童鞋们都能看得懂。希望你对element-ui,vu...【详细内容】
2022-03-16  Search: JS函数  点击:(338)  评论:(0)  加入收藏
常用的前端js函数封装,可以直接用
1、输入一个值,返回其数据类型function type(para) { return Object.prototype.toString.call(para)}2、数组去重function unique1(arr) { return [...new Set(arr)]}f...【详细内容】
2021-04-02  Search: JS函数  点击:(444)  评论:(0)  加入收藏
js函数常见的写法以及调用方法
1:常规写法//函数的写法function run{alert("常规写法") //这里是你函数的内容}//调用run()2:匿名函数写法var run = function(){alert("这是一种声明函数的写法,左边是一...【详细内容】
2019-11-07  Search: JS函数  点击:(545)  评论:(0)  加入收藏
js函数回调
回调函数,什么是回调函数呢?很多初学者都不是很明白,感觉懵懵的,不理解,更不会用!其实简单理解的话就是在一个函数执行完毕后,得到想要的特定数据后在去执行的函数,并没有性药中的那...【详细内容】
2019-10-16  Search: JS函数  点击:(712)  评论:(0)  加入收藏
▌简易百科推荐
JavaScript的异步编程常见模式
在JavaScript中,异步编程是一种处理长时间运行操作(如网络请求或I/O操作)的常见方式。它允许程序在等待这些操作完成时继续执行其他任务,从而提高应用程序的响应性和性能。JavaS...【详细内容】
2024-04-12  靳国梁    Tags:JavaScript   点击:(6)  评论:(0)  加入收藏
17 个你需要知道的 JavaScript 优化技巧
你可能一直在使用JavaScript搞开发,但很多时候你可能对它提供的最新功能并不感冒,尽管这些功能在无需编写额外代码的情况下就可以解决你的问题。作为前端开发人员,我们必须了解...【详细内容】
2024-04-03  前端新世界  微信公众号  Tags:JavaScript   点击:(6)  评论:(0)  加入收藏
你不可不知的 15 个 JavaScript 小贴士
在掌握如何编写JavaScript代码之后,那么就进阶到实践——如何真正地解决问题。我们需要更改JS代码使其更简单、更易于阅读,因为这样的程序更易于团队成员之间紧密协...【详细内容】
2024-03-21  前端新世界  微信公众号  Tags:JavaScript   点击:(29)  评论:(0)  加入收藏
又出新JS运行时了!JS运行时大盘点
Node.js是基于Google V8引擎的JavaScript运行时,以非阻塞I/O和事件驱动架构为特色,实现全栈开发。它跨平台且拥有丰富的生态系统,但也面临安全性、TypeScript支持和性能等挑战...【详细内容】
2024-03-21  前端充电宝  微信公众号  Tags:JS   点击:(28)  评论:(0)  加入收藏
构建一个通用灵活的JavaScript插件系统?看完你也会!
在软件开发中,插件系统为应用程序提供了巨大的灵活性和可扩展性。它们允许开发者在不修改核心代码的情况下扩展和定制应用程序的功能。本文将详细介绍如何构建一个灵活的Java...【详细内容】
2024-03-20  前端历险记  微信公众号  Tags:JavaScript   点击:(23)  评论:(0)  加入收藏
对JavaScript代码压缩有什么好处?
对JavaScript代码进行压缩主要带来以下好处: 减小文件大小:通过移除代码中的空白符、换行符、注释,以及缩短变量名等方式,可以显著减小JavaScript文件的大小。这有助于减少网页...【详细内容】
2024-03-13  WangLiwen    Tags:JavaScript   点击:(5)  评论:(0)  加入收藏
跨端轻量JavaScript引擎的实现与探索
一、JavaScript 1.JavaScript语言JavaScript是ECMAScript的实现,由ECMA 39(欧洲计算机制造商协会39号技术委员会)负责制定ECMAScript标准。ECMAScript发展史: 2.JavaScript...【详细内容】
2024-03-12  京东云开发者    Tags:JavaScript   点击:(6)  评论:(0)  加入收藏
面向AI工程的五大JavaScript工具
令许多人惊讶的是,一向在Web开发领域中大放异彩的JavaScript在开发使用大语言模型(LLM)的应用程序方面同样大有价值。我们在本文中将介绍面向AI工程的五大工具,并为希望将LLM...【详细内容】
2024-02-06    51CTO  Tags:JavaScript   点击:(55)  评论:(0)  加入收藏
JS小知识,使用这6个小技巧,避免过多的使用 if 语句
最近在重构我的代码时,我注意到早期的代码使用了太多的 if 语句,达到了我以前从未见过的程度。这就是为什么我认为分享这些可以帮助我们避免使用过多 if 语句的简单技巧很重要...【详细内容】
2024-01-30  前端达人  今日头条  Tags:JS   点击:(60)  评论:(0)  加入收藏
18个JavaScript技巧:编写简洁高效的代码
本文翻译自 18 JavaScript Tips : You Should Know for Clean and Efficient Code,作者:Shefali, 略有删改。在这篇文章中,我将分享18个JavaScript技巧,以及一些你应该知道的示例...【详细内容】
2024-01-30  南城大前端  微信公众号  Tags:JavaScript   点击:(76)  评论:(0)  加入收藏
站内最新
站内热门
站内头条