本文适用于对 Vue.js 和 vue-router 有一定程度了解的开发者,除特殊说明,vue-router 版本为 3.0.2
2020 年4月本文更新时,vue-router 版本为 3.1.6
正文
路由 class 匹配
<router-link>
路由匹配后会给该标签添加 class 属性值.router-link-active
,该功能在嵌套路由中十分方便class 的实际属性值可以通过
的 active-class
来控制,全局默认值则通过路由构造选项linkActiveClass
来控制默认情况下,当前路由的所有父级会默认添加
active-class
,即 当前处于/user/1
会给当前页面的<router-link to="/">
添加active-class
,如果不需要此项,给<router-link>
添加exact
即可,精准匹配的 class 通过exact-active-class
控制示例:JSFiddle
通配符路由
路由配置:
{path: '/user-*'}
,访问/user-admin
路由,可在$route.params.pathMatch
获取到'admin'
(pathMatch 仅在vue-router@3.0.2+
可用,低于此版本使用$route.params[0]
尝试获取)示例:JSFiddle
路由高级匹配模式
vue-router 使用 path-to-regexp 作为路由匹配引擎,该库可以通过输入的路径生成匹配规则的正则表达式,从而实现路由匹配功能。
path-to-regexp
中常用的方法pathToRegexp(path, keys, options)
第三个参数为pathToRegexpOptions
编译正则的选项,在vue-router@2.6.0+
版本可以通过配置route
的pathToRegexpOptions
参数添加高级配选项。参考例子,其可通过
'/optional-params/:foo?'
实现可选param
,也可通过'/params-with-regex/:id(\\d+)'
实现仅匹配数字param
(非命中路由向后匹配)。pathToRegexpOptions
的内容为:- sensitive 大小写敏感 (default: false)
- strict 末尾斜杠是否精确匹配 (default: false)
- end 全局匹配 (default: true)
- start 从开始位置展开匹配 (default: true)
- delimiter 指定其他分隔符 (default: '/')
- endsWith 指定标准的结束字符
- whitelist 指定分隔符列表 (default: undefined, any character)
编程式导航的钩子处理
在
vue-router@2.2.0+
,可选的在router.push
或router.replace
中提供onComplete
和onAbort
回调作为第二个和第三个参数。这些回调将会在导航成功完成 (在所有的异步钩子被解析之后) 或终止 (导航到相同的路由、或在当前导航完成之前导航到另一个不同的路由) 的时候进行相应的调用。该功能可用在少数埋点场景,而不用配置复杂的路由钩子。路由重定向
给
route
配置redirect
属性可使路由重定向到指定路由,该属性支持String/Object/Function
三种类型的值,其中Function
的参数为to
对象给重定向的中间路由添加
beforeEach
和beforeLeave
不会有效果,给router
添加的钩子也不能检测到此次重定向,如果需要判断重定向来源,可使用路由对象$route.redirectedFrom
判断该功能适合路由
path
修改后保留原路由的重定向文档:重定向
嵌套命名视图
在平级展示多个视图时(单个视图使用多个平级的
<router-view>
),可以用到<router-view>
的name
prop 例如在sidebar/list
的布局页面上,不用在父级视图容器去书写许多子组件的逻辑,只需要在路由配置中配置好相关页面组件,从而进行组件关系解耦,也能高效控制子视图渲染例子:JSFiddle
文档:嵌套命名视图
路由别名
给
route
配置alias
属性可以使访问者保持原有url
却访问到指定路由中去。该属性支持
String
和Array
两种类型,当alias
与其他路由重复时,以先申明的路由为准,同时别名不会进行路由 class 匹配文档:别名
路由组件传参
该功能旨在给组件与路由解除耦合关系,给
route
配置props: true
同时组件内props
配置与prams
相同的变量,可以直接通过访问props
而不用通过$route.params
去访问参数如果
props
是一个对象,对象内容会当作静态内容传入组件作为props
当
props
为一个函数,函数接收一个route
参数,可以使query
作为props
传入组件或实现更多高级功能文档:路由组件传参
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用离开守卫。
- 调用全局的 beforeEach 守卫。
- 在重用的组件里调用 beforeRouteUpdate 守卫 (vue-router@2.2+)。
- 在路由配置里调用 beforeEnter。
- 解析异步路由组件。
- 在被激活的组件里调用 beforeRouteEnter。
- 调用全局的 beforeResolve 守卫 (vue-router@2.5+)。
- 导航被确认。
- 调用全局的 afterEach 钩子。
- 触发 DOM 更新。
- 用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
文档:完整的导航解析流程
滚动行为
创建 Router 实例,可以提供一个
scrollBehavior
方法,该方法接收to
、from
、savedPosition
(该页面原存在的 xy 值,仅在通过浏览器前进后退中可用)在该方法中返回
{selector:to.hash}
还可实现类似于“滚动到锚点”的行为,vue-router@2.6.0+
还可返回{offset?:{x,y}}
进行位置偏移,注意该偏移负值为向负方向偏移其
异步滚动
通常用于小众的过渡组件(transition)和滚动行为同时进行的情况下,官方实例未给太多相关信息文档:滚动行为
组件懒加载-按组分块
SPA(single page application)由于 All in JS 的特性,会使得首屏加载比较慢,很多人都推荐使用 Webpack 的 代码分割功能减小单个 JS 体积,当所有页面组件使用动态加载则会使页面请求过多而得不偿失,所以组件按组分块则应运而生:
const Foo = () => import(/* webpackChunkName: "group-foo" */ "./Foo.vue"); const Bar = () => import(/* webpackChunkName: "group-foo" */ "./Bar.vue"); const Baz = () => import(/* webpackChunkName: "group-foo" */ "./Baz.vue");
该功能需要
webpack@2.4+
支持文档:把组件按组分块
获取路由匹配组件
router.getMatchedComponents(location?)
该函数可以获取传入参数在路由表中匹配的路由对象数组,官方文档中写到通常在服务端渲染数据预加载的时候,也可用于在获取当前路由对象数组的时候
如果需要获取当前路由记录(就是路由构造选项 routes 配置数组中的对象副本,包含 children 数组),可用
route.matched
解析路由
router.resolve(location, current?, append?)
该函数可同时导出一个类似浏览器的
location
对象和一个根据匹配到的路由记录resolved
,如果没有匹配到对应的对象,resolved
字段默认返回 404 组件或错误数据添加路由
router.addRoutes(routes:Array<RouteConfig>)
该函数可以用户触发添加路由到路由表中,可以尝试在用户权限控制中使用
以下内容于 2020 年 4 月更新
- 增加 Browser ESM 构建产物 for 3.0.4
在支持 EcmaScript Module 的浏览器中,你可以这样使用 vue-router
<script type="module">
import VueRouter from "https://cdn.jsdelivr.net/npm/vue-router@^3.0.4/dist/vue-router.esm.browser.js";
</script>
- 编程式导航的钩子增加 Promise 返回 for 3.1.0
上文中编程式导航钩子未传入第二个和第三个参数时,push 和 replace 方法将返回 Promise,使用代码解释为:
router.push(location, onComplete?, onAbort?)
router.push(location).then(onComplete).catch(onAbort)
router.replace(location, onComplete?, onAbort?)
router.replace(location).then(onComplete).catch(onAbort)
- <router-link> v-slot for 3.1.0
router-link 通过作用域插槽(v-slot)使内部内部组件具有 router-link 的能力
该功能可用于 将激活的 class 应用在外层元素
<router-link
to="/foo"
v-slot="{ href, route, navigate, isActive, isExactActive }"
>
<li
:class="[isActive && 'router-link-active', isExactActive && 'router-link-exact-active']"
>
<a :href="href" @click="navigate">{{ route.fullPath }}</a>
</li>
</router-link>
这样即可使 <li>
具有激活的 class
最佳实践
简单按钮的路由跳转逻辑不使用
v-on:click
事件,多使用<router-link>
标签。如果 SPA 放置路径处于域名的子目录中,不要按照一些网络教程写的去修改 webpack 配置,应该修改
Router 构建选项
中的base
值,这样能避免一些不必要的问题不要尝试改变组件内的
$route
的内容,这个属性是只读,里面的属性是immutable
状态,但你可以watch
这个
更新后记
该文章最后更新于2020年4月,此时 vue-router@4.0.0-alpha 已经发布了七个版本,故此文将不再更新,如果有相关后续文章,将从 vue-router 源码方向解读 API