Vue-Router Note
Vue Router (https://github.com/vuejs/vue-router) 使用笔记。虽然官方文档比较详尽,但实际用起来依然有些地方需要特别注意的(其实主要是我的个人需求)。
Scroll Behaviours
文档上有 scroll behaviours 的示例,但实际上用起来不太完美,还需要自己改造一下。需要注意的是 scrollBehavior
必须搭配 history
模式,否则代码无效且无任何错误信息。
上面说到不完美的地方主要是在模拟 ‘scroll to anchor’ 这一行为时,文档的代码是不够好的:
scrollBehavior (to, from, savedPosition) { |
这里实际上会调用 querySelector(to.hash)
来实现滚动,但是用起来会发现有些时候这段会报错,因为类似 #1-anything
这样的数字(或者其他非字母字符)打头的 hash 作为 selector 是 Invalid 的。但是要修复只需要稍微改动一下就好了:
if (to.hash) { |
所以一段完善的 scroll behaviour 代码应该是:
scrollBehavior (to, from, savedPosition) { |
它可以做到在路由变化时:
- 有锚点时滚动到锚点
- 有历史位置时滚动到历史位置
- 都没有时滚动到页头
Lazy Loading
官方的 Lazy load 示例代码换了很多茬,比如之前有类似 require('...', resolve)
的,还有用 System.import
的,但是它们并不能向后兼容,所以如果用的是新版本的话,并不能够直接 copy 旧项目的方式。目前感觉会稳定下来的方式是:
const Foo = () => import('./Foo.vue') |
但是这里又有一个注意点,以上语法必须引入一个 babel 插件 syntax-dynamic-import 才行:
npm install --save-dev babel-plugin-syntax-dynamic-import |
.babelrc
{ |
以上就可以在 webpack + babel 的环境下实现代码分块了。
Progress
经常会有这样的需求(尤其是使用 lazy load 时):路由跳转时提供一个进度条(像 Github 头部那种),然而 Vue Router 没有提供这方面的示例。经过实际使用发现,并不需要刻意使用 Vue 封装的进度条,比如说轻量级的 nprogress 也可以很好地搭配使用。
但是需要注意的是,Vue Router 会将 hash 跳转也视为一次 route 跳转,因此如果在全局钩子中注册 progress 方法的话,那么它也会在 hash 跳转中出现,实际上应该是不需要的。所以需要一点点判断:
import NProgress from 'nprogress' |
以上就是一个简单的页面跳转进度条示例,它会在除了同页 hash 跳转以外的所有页面跳转行为发生时,在页头显示一个简单的进度条。
Active Style
当使用 <router-link>
的时候,Vue Router 会自动给当前路由的 link 加一个 active class,用来做 nav menu 时非常方便。但是有一点需要注意的是,它默认并不是一个精确匹配的模式,而是一个 matchStart,比如说 <router-link to="/a">
会被一个 /a/b
的路由激活,更甚者,<router-link to="/">
会被所有路由激活(真的)。然而这一般来说都不会是想要的结果。
在老旧版本(0.x)的 Vue-Router 中这个问题是无解的,现在则可以使用 <router-link exact>
来将它转换为精确匹配。
Route Reuse
当使用 <router-view>
时,默认会启用组件复用,也就是说在可能的情况下,作为路由页面的组件不会被销毁重建,而是直接复用。
就好像一个博客的文章页面,一般来说会是给出这样的路由配置:/post/:id
,那么在从 /post/1
跳转到 /post/2
的时候,实际上路由组件是不会重建的。
有时候我们会想要避免这样的事情发生,因为一个路由可能在创建的时候有比较多的逻辑(如数据动态获取、判断等),如果它在路由变化的时候直接复用的话,那么 mount
方法将不再被调用,我们还要为 update
再写一套类似的逻辑。更过分的是,其所用到的所有子组件也不再会执行 mount
方法,那么我们要为所有子组件编写 update
方法。非常麻烦。
不知道为什么,老版本的文档是有为这种情况提供解决方案的,但是在现在的文档里面找不到了。实际上很简单:
<router-view :key="$route.path"></router-view> |
就这样就可以了。如此一来,只要在 $route.path
变化的时候,路由组件就会被销毁重建。用一点点的性能损耗,节省大量冗余代码。
当然这里也可以使用定制化逻辑来控制,比如使用 computed value 来实现更复杂的复用逻辑。