这是 Vue 全家桶组件系列的文章,梳理一下比较难懂的几个点,此篇文章要说的就是 Vue-Router
什么是路由
在 web 领域,我们可以将 路由 简单的理解为 控制器, 这个控制器主要做什么呢?它能将输入到浏览器中的 url 导向至对应页面的组件,然后浏览器就将这个组件渲染出来。这个过程就是 路由 。
什么是 Vue-Router
以下是官方说明:
Vue Router 是 Vue.js 官方的 路由管理器
其实跟 Vuex 的思想是很像的,它通过一个全局的router
,来对浏览器中的 url 进行管理,最后导向不同的页面。
核心概念
主要有几大核心概念
- 动态路由匹配
- 重定向和别名
- 路由组件传参
- History 模式
- 导航守卫
- 路由懒加载
动态路由匹配
什么是动态路由匹配?比如我输入的 url 中有 /user/foo
和 /user/bar
,我们希望在输入这两个 url 后导向的是同一个页面的同一个组件,那么我们可以这么写(类似于用个变量代替 /user/
后面的参数,然后就往这个变量丢参数就完事儿了,因为不写死,所以就是动态的)
// User 组件 |
同时在 path
中也可以设置多段 路径的参数,比如我想要输入 /user/foo/post/100
,你可以这样写
/user/:id/post/:post_id |
当然了,动态路径的参数名字是可以随便取的,我们可以在 $route.params
中看到这个
console.log($route.params); // {id: 'foo', post_id: '100'} |
注意一下这里的匹配优先级,若存在多个路径匹配同一个路由的情况,如
const router = new VueRouter({ |
那么会优先匹配先定义的,也就是输入 /xxx
,会匹配到 User1
重定向和别名
Vue-Router 的这个功能可以实现一个逻辑,这个逻辑是什么呢?拿知乎来举例,若我是未登录的状态,那么当访问个人信息页面时,应该重定向到登录页面,如下
const router = new VueRouter({ |
也可以是一个已经命名过的路由
const router = new VueRouter({ |
也可以是一个方法
const router = new VueRouter({ |
同样,你可以用 别名 的方式,什么是别名?比如在浏览器中输入的是 /bar
,但实际上访问的是 /foo
const router = new VueRouter({ |
路由组件传参
什么是路由组件传参?我们可以这么理解,其实就是在浏览器输入一串 url ,然后渲染的对应组件能够接受到这串 url 中的某些参数,这就是
参数 |
路由组件传参有 3 种方式: 布尔模式、对象模式、函数模式
- 布尔模式
其实就是通过 props
传参,比如我输入 /user/foo
这个 url,我想把 url 中 foo
这个参数传给组件,可以这么写
// User 组件 |
前提条件是要设置对应匹配路由的 props
为 true
如果你在使用 router-view
时使用到了 name
这个属性,比如
// 渲染 user |
你就需要为每个对应的 命名视图
添加 props
const router = new VueRouter({ |
- 对象模式
比如组件中 props
是个对象
// User 组件 |
- 函数模式
其实本质上这个函数返回的还是一个对象,比如在浏览器中输入 /search?name=strugglebak
表示查询,可以这么写
// User 组件 |
router.query.name
返回的就是 strugglebak
这个字符串
History 模式
什么是 History 模式?我们知道,网易云的 url 一般来说是这种形式
http://music.163.com/#/my/m/music/playlist?id=121597667 |
在播放歌曲时,每个 url 下都有一个 #
符号,我们知道这个符号是 url 的 hash 部分,这个符号后面那一大串不会传递到服务端,那么它有什么用?它的作用就是 通过这个 hash 来模拟传统的后端路由器,判断哪些请求可以直接导向哪个组件,进而渲染出这个组件,这就是前端路由器的作用。但是带个 #
号的 url 看起来比较丑,你看哪些传统的 web 应用的 url 就没有,那么有没有一种办法来去掉这个 #
号呢?
有的,Vue-Router 提供了这个 History模式,你只需要做如下设置
const router = new VueRouter({ |
url 就会和正常的 url 一样没有 #
号,就对 url 进行了美化处理
但是这个还需要后端配置,官方文档是这么说的
不过这种模式要玩好,还需要后台配置支持。因为我们的应用是个单页客户端应用,如果后台没有正确的配置,当用户在浏览器直接访问 http://oursite.com/user/id 就会返回 404,这就不好看了。
所以呢,你要在服务端增加一个覆盖所有情况的候选资源:如果 URL 匹配不到任何静态资源,则应该返回同一个 index.html 页面,这个页面就是你 app 依赖的页面。
导航守卫
什么是导航守卫呢?这其实就相当于一个 拦截器,在路由发生变化的之中通过这层拦截来实现一些业务需求。一般来说,我们认为当你点击 a 链接进行 重定向式跳转 时路由就产生 变化 了。
但是这里需要注意,params 或者 query 的变化并不会触发 enter/leave 这类路由拦截器,你可以通过
const User = { |
或者
const User = { |
这样的方式来监听以上的变化
导航守卫有几个 api,分别是
- 全局的守卫
beforeEach
,beforeResolve
,afterEach
- 路由独享守卫
beforeEnter
- 组件内的守卫
beforeRouterEnter
,beforeRouterUpdate
,beforeRouterLeave
首先我们应该先看看一个完整的导航解析过程是怎样的
(失活组件)beforeRouterLeave |
基本上解析过程就代表了它们之间的区别了
注意 beforeEnter
是 可以 在路由配置上定义
const router = new VueRouter({ |
以及组件内的路由用法如下
// Foo 组件 |
路由懒加载
路由的懒加载是什么呢?一般我们使用 webpack 进行打包时,js 代码会变得很大,这样会对页面加载的性能造成影响,如何提升性能呢?就是 按需加载,当路由被访问的时候才加载对应组件。具体要怎么做呢?就是分离组件代码。
这里需要分两步来做
将异步组件定义为返回一个 Promise 的工厂函数
const Foo = () => Promise.resolve({ /* 组件定义对象 */ })
在 webpack 中 import
import('./Foo.vue').then((module)=> {
//...
})
还有其他常用 API
常用 API 有 router-link
/router-view
/this.$router.push
/this.$router.replace
/this.$route.params
router-link
一般写在需要进行路由跳转的地方,它最终渲染的是一个 a 标签
<!-- 使用字符串 --> |
router-view
如果 router-view
设置了名称,则会渲染对应的路由配置中 components
下的相应组件,一般我们是这么写
<!-- 渲染一个 name 为 main 的组件 --> |
然后在路由中有如下配置
const router = new VueRouter({ |
this.$router.push
一个 router-link
的替代品,作用就是 向 history 添加记录,可以有如下用法
// 字符串 |
注意,若写了 path
,则 params
会被忽略掉(query
除外),所以你应该这么写
const userId = '123' |
this.$router.replace
跟上面的 push
方法很像,不过作用是 替换掉当前的 history 记录,用法跟上面的相同
this.$router.params
就是一个 key/value
对象,之前在 动态路由匹配 中说过,它里面保存的就是路由参数
总结
Vue-Router 是前端 SPA 项目的利器,它可以提升用户的体验,增加开发效率。本文只是简单梳理了一下 Vue-Router 开发经常会用到的东西,其他小细节还得多去翻翻 官方文档