• 开始时间:2020-01-27
  • 目标主要版本:Vue 3 Router 4
  • 引用 issue:issues
  • 实现的 PR:

摘要

引入一个 API,允许在路由工作时添加和删除路由记录。

  • router.addRoute(route: RouteRecord) 添加一个新路由
  • router.removeRoute(name: string | symbol) 删除一个现有的路由
  • router.hasRoute(name: string | symbol): boolean 坚持路由是否存在
  • router.getRoutes(): RouteRecord[] 获取当前的路由列表

基本范例

给出一个正在运行的 app 中的 router 实例:

  1. router.addRoute({
  2. path: '/new-route',
  3. name: 'NewRoute',
  4. component: NewRoute
  5. })
  6. // add to the children of an existing route
  7. router.addRoute('ParentRoute', {
  8. path: 'new-route',
  9. name: 'NewRoute',
  10. component: NewRoute
  11. })
  12. router.removeRoute('NewRoute')
  13. // normalized version of the records added
  14. const routeRecords = router.getRoutes()

动机

动态路由是一种功能,它使应用程序能够建立自己的路由系统。这方面的一个案例时 vue-cli ui,它允许添加徒刑插件,这些插件可以有自己的借口。

当前版本的 Vue Router 只支持添加一个新的绝对(absolute)路由。这个 RFC 的想法是添加缺失的功能以允许动态路由。思考这个 API 的不同塑造方式,以及什么对 Vue Router 的未来是最好的。目前,如果不进行黑客方式或者创建一个全新的 Router 实例,就不可能实现上面描述的例子。

从理论上讲,这也可以通过 HMR(Hot Module Replacement,热模块替换)的方式,在原地改变 routes 来改善开发者的体验。

注意:动态路由只有在实现了路径排名(自动路由顺序,允许任何顺序添加路由记录,但仍然能正确匹配)才有意义。添加这个功能的大部分成本是在给路径评分上面。

具体设计

addRoute

  • 允许添加一个绝对路由
  • 允许添加一个子路由
  • 应该如何处理冲突?
  • 函数应该返回什么?

代码范例是用 TS 写的,以提供更多关于预期对象的信息:

RouteRecord 是在给实例化 Router 时在 routes 选项中使用的同一类对象。为了给你一个概念,它看起来像(https://router.vuejs.org/api/#routes)。需要注意的是,这个对象与 routes 选项是一致的,因为 RouteRecord 类型在未来的 Vue Router 4 版本中可能会有小的变化。

  1. const routeRecord: RouteRecord = {
  2. path: '/new-route',
  3. name: 'NewRoute',
  4. component: NewRoute
  5. }

对于从 addRoute 返回的内容有不同的选项。

返回一个允许删除路由的函数,对未命名的路由很有用。

  1. const removeRoute = router.addRoute(routeRecord)
  2. removeRoute() // removes the route record
  3. // or
  4. router.removeRoute('NewRoute') // because names are unique

如果我们在 /new-route 上,添加记录将不会触发替换导航。用户负责通过调用 router.pushrouter.replace 与当前 location router.replace(router.currentRoute.value.fullPath) 来强制进行导航(navigation)。使用 location 的字符串版本可以确保解决一个新的 location 而不是旧的 location。如果路由被添加到一个导航守卫(navigation guard)内,要确保使用 to 参数的值:

  1. router.beforeEach((to, from, next) => {
  2. // ...
  3. router.addRoute(newRoute)
  4. next(to.fullPath)
  5. // ...
  6. })

因为动态路由 API 是一个高级的 API,大多数用户不会直接使用,有了这种分割,可以使行为更加灵活和优化。建议添加路由的方法仍然是基于配置的方法。

替代品,请查看备选方案

冲突

当添加一个与现有路由同名的路由时,它应该替换现有的路由。这是最方便的版本,因为它允许替换新的 routes,而不必在使用相同的名称时明确地删除旧的路由。

备选方案:

  • 失败并抛出一个错误,要求用户先替换它:不太方便
  • 不警告用户,但仍要替换它:可能会出现难以调试的错误

嵌套 routes

根据 addRoute 返回的内容,可以通过引用现有路由的名称来添加一个嵌套路由。这强制父路由被命名。

  1. router.addRoute('ParentRoute', routeRecord)

签名

  1. interface addRoute {
  2. (parentName: string | symbol, route: RouteRecord): () => void
  3. (route: RouteRecord): () => void
  4. }

removeRoute

移除一个路由也会移除它的所有子路由。和 addRoute 一样,有必要触发一个新的导航,以便通过 RouterView 更新当前显示的视图。

  1. interface removeRoute {
  2. (name: string | symbol): void
  3. }

hasRoute

检查路由是否存在:

  1. interface hasRoute {
  2. (name: string | symbol): boolean
  3. }

getRoutes

允许读取规范化路由记录的列表:

  1. interface getRoutes {
  2. (): RouteRecordNormalized[]
  3. }

RouteRecordNormalized 中的内容有待决定,但至少包含了 RouteRecord 的所有现有属性,其中一些已经被规范化(比如,是 components 而不是 componentundefined 名称)。

缺点

这个 API 增加了 vue-router 的大小。要让它成为 treeshakable 的就需要允许 matcher(负责解析 path 和进行 path 排名)扩展出更简单的版本,这一点写起来相当复杂,但我们可以转而输出不同版本的 matcher,并允许用户在更精简的 router 中指定 matcher。

备选方案

addRoutes

  • 一个 promise,根据添加记录可能触发的导航来 resolve 或 reject(例如,在添加路由前在 /new-route 上)。 ``typescript window.location.pathname // "/new-route" // 1. The promise of a function that allows removing the route record const removeRoute = await router.addRoute(routeRecord) // 2. The same kind of promise returned byrouter.push`. const route = await router.addRoute(routeRecord)

removeRoute() // removes the route record // or router.removeRoute(‘NewRoute’) // names are unique

  1. - 对所添加记录的引用(原始记录的规范化副本)
  2. ```typescript
  3. // js object (same reference hold by the router)
  4. const normalizedRouteRecord = router.addRoute(routeRecord)
  5. router.removeRoute(normalizedRouteRecord)

getRoutes

路由也可能有一个响应式的属性,但这将允许在模版中使用它们,在大多数情况下,这是一个应用程序层面的功能,并且应该以另一种方式来处理事情,有一个响应式的路由记录来源,与 router 同步。在应用层面这样做,可以避免为每个用户增加成本。

采纳策略

  • 废弃 addRoutes,在 Vue Router 3 中添加 addRoute。其他方法是新的。

没有解决的问题

N/A