vue-router详解

认识 vue-router
  • vue-router是Vue.js官方的路由插件,它和vue.js是深度集成的,适合用于构建单页面应用。

  • 我们可以访问其官方网站对其进行学习: https://router.vuejs.org/zh/

  • vue-router是基于路由和组件的:

    • 路由用于设定访问路径, 将路径和组件映射起来。

    • 在vue-router的单页面应用中, 页面的路径的改变就是组件的切换。

安装和使用 vue-router
安装vue-router
1
npm install vue-router --save
在模块化工程中使用
  • 第一步:导入路由对象,并且调用 Vue.use(VueRouter)

  • 第二步:创建路由实例,并且传入路由映射配置

  • 第三步:在Vue实例中挂载创建的路由实例

1
2
3
4
import Vue from 'vue' 
import VueRouter from 'vue-router'

Vue.use(VueRouter)
使用 vue-router 的步骤
  • 第一步: 创建路由组件

  • 第二步: 配置路由映射: 组件和路径映射关系

  • 第三步: 使用路由: 通过<router-link><router-view>

操作演示
创建 router 实例

挂载到Vue实例中

创建路由组件

配置组件和路径的映射关系

使用路由

说明:

  • <router-link>: 该标签是一个vue-router中已经内置的组件, 它会被渲染成一个<a>标签.
  • <router-view>: 该标签会根据当前的路径, 动态渲染出不同的组件.
  • 网页的其他内容, 比如顶部的标题/导航, 或者底部的一些版权信息等会和<router-view>处于同一个等级.
    在路由切换时, 切换的是<router-view>挂载的组件, 其他内容不会发生改变.
效果

设置路由的默认路径

需求:默认情况下, 进入网站的首页, 我们希望<router-view>渲染首页的内容.但是我们的实现中, 默认没有显示首页组件, 必须让用户点击才可以.

问题:如何可以让路径默认跳到到首页, 并且<router-view>渲染首页组件呢?

方案:多配置一个映射

配置解析:

  • 我们在routes中又配置了一个映射.
  • path配置的是根路径: /
  • redirect是重定向, 也就是我们将根路径重定向到/home的路径下, 这样就可以得到我们想要的结果了
History 模式

History模式:路径显示中不含 # (vue默认路径显示方式为hash模式,路径中带有#,可以参考上面的运行截图)

如果希望使用HTML5的history模式, 非常简单, 进行如下配置即可:

效果:

一些属性

tag: 可以指定<router-link>之后渲染成什么组件, 比如下面的代码会被渲染成一个<li>元素, 而不是<a>

1
<router-link to='/home' tag='li'>

replace: replace不会留下history记录, 所以指定replace的情况下, 后退键返回不能返回到上一个页面中

active-class:<router-link>对应的路由匹配成功时, 会自动给当前元素设置一个router-link-active的class, 设置active-class可以修改默认的名称。在进行高亮显示的导航菜单或者底部tabbar时, 会使用到该类.
但是通常不会修改类的属性, 会直接使用默认的router-link-active即可.

该class具体的名称也可以通过router实例的属性进行修改:

可以看到 后面第二个class的名称变成了 active

路由代码跳转

有时候, 页面的跳转可能需要执行对应的JavaScript代码, 这个时候, 就可以使用第二种跳转方式了
比如, 我们将代码修改如下:

动态路由

在某些情况下,一个页面的path路径可能是不确定的,比如我们进入用户界面时,希望是如下的路径:
/user/zhangsan或/user/lisi
除了有前面的/user之外,后面还跟上了用户的ID,这种path和Component的匹配关系,我们称之为动态路由(也是路由传递数据的一种方式)。

方式:

1
path: '/user/:id'

懒加载

官方解释:当打包构建应用时,Javascript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就更加高效了

懒加载做了什么?
  • 路由懒加载的主要作用就是将路由对应的组件打包成一个个的js代码块.
  • 只有在这个路由被访问到的时候, 才加载对应的组件
方式

在ES6中, 我们有更加简单的写法:

1
const Home = () => import('../components/home.vue')
效果

图片15

嵌套路由
概述

嵌套路由是一个很常见的功能

  • 比如在home页面中, 我们希望通过/home/news和/home/message访问一些内容.
  • 一个路径映射一个组件, 访问这两个路径也会分别渲染两个组件.

路径和组件关系如下:

步骤
  • 创建对应的子组件, 并且在路由映射中配置对应的子路由.
  • 在组件内部使用<router-view>标签.
使用演示

创建home页面的两个字组件页面 message 页面 和 news 页面

因为创建的两个组件是home下的,因此在配置路径时,为home添加children属性,并在children内配置message和news的路径(不加 斜杠 /),如下

在home页面配置字组件的路由连接和显示 通过 <router-link><router-view>标签

效果

嵌套路由默认路径

配置示意如下:

传递参数
方式
  • params的类型:

    • 配置路由格式: /router/:id
    • 传递的方式: 在path后面跟上对应的值
    • 传递后形成的路径: /router/123, /router/abc
  • query的类型:

    • query是对象的形式,变量 key-value 方式存在

    • 配置路由格式: /router, 也就是普通配置

    • 传递的方式: 对象中使用query的key作为传递方式
    • 传递后形成的路径: /router?id=123, /router?id=abc
  • 示例

    1
    2
    3
    4
    5
    // params 类型 to 绑定的相当于一个字符串
    <router-link :to="'/user/'+userId">用户</router-link>

    //query 类型 to 绑定的相当于一个对象,对象内有两个变量 path 和 query,并且query也是对象的形式
    <router-link :to="{path: '/profile',query: {name: 'zx',id: userId}}">档案</router-link>
使用

使用也有两种方式:

  • <router-link>的方式
  • JavaScript代码方式

先创建一个新的组件Profile.vue,并配置好路由映射

配置router-link

可以明显看出,和 params 方式的不同之处:params

操作演示 JavaScript方式

也是很简单,调用this.$router.push() 里面传入一个对象即可,对象包含两个变量 一个path,一盒query

获取传递的参数
  • 获取 params 方式传递的参数

    1
    $route.params
  • 获取 query 方式传递的参数:

    1
    2
    3
    4
    //获取整个query对象
    $route.query
    //获取query对象中的某个key的value值
    $route.query.name

获取参数通过$route对象获取的,在使用了vue-router 的应用中,路由对象会被注入每个组件中,赋值为this.$route,并且当路由切换时,路由对象会被更新。获取传递的信息如下:

$route$router的区别
  • $router为VueRouter实例,想要导航到不同URL,则使用$router.push方法
  • $route为当前router跳转对象里面可以获取name、path、query、params

导航守卫
官网

https://router.vuejs.org/zh/guide/advanced/navigation-guards.html#%E5%85%A8%E5%B1%80%E5%90%8E%E7%BD%AE%E9%92%A9%E5%AD%90

vue-router提供的导航守卫主要用来监听监听路由的进入和离开的.
vue-router提供了beforeEach和afterEach的钩子函数, 它们会在路由即将改变前和改变后触发.

beforeEach
1
2
3
4
5
router.beforeEach((to, from, next) => {
//to and from are Route Object,next() must be called to resolve the hook}
window.document.title = to.meta.title
next()
})

导航钩子的三个参数解析:

  • to: 即将要进入的目标的路由对象。

  • from: 当前导航即将要离开的路由对象。

  • next: 调用该方法后, 才能进入下一个钩子. 该方法必须调用,否则无法完成正常跳转。

  • next的几种使用

    • next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
    • next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
    • next(‘/‘) 或者 next({ path: ‘/‘ }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next 传递任意位置对象,且允许设置诸如 replace: true、name: ‘home’ 之类的选项以及任何用在 router-link 的 to prop 或 router.push 中的选项。
    • next(error): (2.4.0+) 如果传入 next 的参数是一个 Error 实例,则导航会被终止且该错误会被传递给 router.onError() 注册过的回调。
afterEach
1
2
3
router.afterEach((to, from) => {
// ...
})
简单示例:beforeEach改变页面标题

路由独享守卫

上面我们使用的导航守卫, 被称之为全局守卫.

可以在路由配置上直接定义 beforeEnter 守卫:

这些守卫与全局前置守卫的方法参数是一样的。

1
2
3
4
5
6
7
8
9
10
11
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内的守卫

可以在路由组件内直接定义以下路由导航守卫:

  • beforeRouteEnter
  • beforeRouteUpdate (2.2 新增)
  • beforeRouteLeave
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const Foo = {
template: `...`,
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}

这个离开守卫通常用来禁止用户在还未保存修改前突然离开。该导航可以通过 next(false) 来取消。

1
2
3
4
5
6
7
8
beforeRouteLeave (to, from , next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
keep-alive
  • keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染。
    它有两个非常重要的属性:
    • include - 字符串或正则表达,只有匹配的组件会被缓存
    • exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存
  • router-view 也是一个组件,如果直接被包在 keep-alive 里面,所有路径匹配到的视图组件都会被缓存:

1
2
3
4
//取消缓存某个组件,注意exclude后面的多个组件名之间不能有空格
<keep-alive exclude="Profile,User">
<router-view/>
</keep-alive>
0%