个人对Vue router的理解,适用初学者

378 阅读7分钟

1.router概述

vue-router是vue官方的路由插件,是和vue深度集成的,适合用于构建单页面的应用,而vue单页面的应用是基于路由和组件的,路由通过path来实现访问不同的路径,将路径和组件进行映射,传统的路由是使用一些超链接来实现页面的切换与跳转,而vue-router则是在单页面的应用中,实现组件之间的切换。其本质是建立起url和页面之间的映射关系

之所以不能使用a标签来实现页面的跳转,是因为当我们的项目在进行打包的时候,运行npm run build的时候,会生成dist文件夹,而在这个文件夹里面只有静态资源和一个index.html页面,此时我们所写的a标签将会失去作用,无法实现页面的跳转。故在实际开发中,使用vue-router是必须的。

2.router的使用方法

首先就是安装安装router,安装完成后按照下列步骤进行操作

  • 1、引入vue-router,并使用Vue.use(VueRouter)
  • 2、定义路由数组,并将数组传入VueRouter实例,并将实例暴露出去
  • 3、将VueRouter实例引入到main.js,并注册到根Vue实例上
// src/router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'
import home from '../components/home.vue'
import hello from '../components/hello.vue'
import homeChild1 from '../components/home-child1.vue'
import homeChild2 from '../components/home-child2.vue'

Vue.use(VueRouter) // 第一步

const routes = [
    {
        path: '/home',
        component: home,
        children: [
            {
                path: 'child1',
                component: homeChild1
            },
            {
                path: 'child2',
                component: homeChild2
            }
        ]
    },
    {
        path: '/hello',
        component: hello,
        children: [
            {
                path: 'child1',
                component: helloChild1
            },
            {
                path: 'child2',
                component: helloChild2
            }
        ]
    },
]

export default new VueRouter({
    routes // 第二步
})

// src/main.js
import router from './router'

new Vue({
  router,  // 第三步
  render: h => h(App)
}).$mount('#app')


4.router的两种模式

(1)Hash模式

hash 模式是用 createWebHashHistory() 创建的,使用URL中的hash来模拟出一个较为完整的URL,当URL发生改变的时候,页面不会重新加载,仅改变#后面的部分,浏览器只会滚动到相应的位置,并不会重新加载网页,更不会被包含在http请求中(但改变#后面的内容仍会被浏览器记录),这样我们就可以使用浏览器的后退功能了

import { createRouter, createWebHashHistory } from 'vue-router'

const router = createRouter({
  history: createWebHashHistory(),
  routes: [
    //...
  ],
})

但该模式会对SEO(即搜索引擎优化)会造成不好的影响,如果担心这点可以更换成其他的模式(网易云便用的Hash模式)

网易云音乐的hash

(2)History模式:

由于Hash模式会在URL中自带#,对于用户来说是影响美感的,所以实际开发中我们更喜欢使用history模式进行开发,看上去也更美观。我们只需要在配置路由中,加入mode:'history',就可以使用了:

//main.js文件中
const router = new VueRouter({
  mode: 'history',
  routes: [...]
})

当使用这种历史模式时,URL 会看起来很 "正常",例如 https://example.com/user/id。漂亮!

不过,问题来了。由于我们的应用是一个单页的客户端应用,如果没有适当的服务器配置,用户在浏览器中直接访问 https://example.com/user/id,就会得到一个 404 错误。这就丑了。

不用担心:要解决这个问题,你需要做的就是在你的服务器上添加一个简单的回退路由。如果 URL 不匹配任何静态资源,它应提供与你的应用程序中的 index.html 相同的页面。漂亮依旧!

总的来说:History模式就是通过pushState()方法来对浏览器的浏览记录进行修改,来达到不用请求后端来渲染的效果

3.router中的属性

(1)path:

  • 类型string

  • 详细内容

    记录的路径。应该以 / 开头,除非该记录是另一条记录的子记录。可以定义参数:/users/:id 匹配 /users/1 以及 /users/posva

    const User = {
      template: '<div>User</div>',
    }
    
    // 这些都会传递给 `createRouter`
    const routes = [
      // 动态字段以冒号开始
      { path: '/users/:id', component: User },
    ]
    

(2)radirect(路由重定向):

  • 类型RouteLocationRaw | (to: RouteLocationNormalized) => RouteLocationRaw (可选)

  • 详细内容

  • 如果路由是直接匹配的,那么重定向到哪里呢。重定向发生在所有导航守卫之前,并以新的目标位置触发一个新的导航。也可以是一个接收目标路由地址并返回我们应该重定向到的位置的函数。

    比如打开一个网站,第一眼看见的,主页面便是redirect,例如很多网站需要先登录上去才可以继续使用,如知乎web端

(3)name:

  • 类型string

  • 默认值"default"

  • 详细内容

    如果 <router-view> 设置了 name,则会渲染对应的路由配置中 components 下的相应组件。

    建议是加入name属性,方便之后的编程式导航,但请注意name是唯一的,不可重复的

    • 演示效果如图所示:

注意:此处只列举出常用的一些属性,更详细的请参考vue router官方文档!

4.导航守卫

(1)概述:

正如其名,vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。

举个例子,当我们想要进入哔哩哔哩的用户界面时,如果此时我们并没有登录上自己的b站账号,那么是不是无法直接跳转到自己的用户信息登录界面,取而代之的是阿b提醒你登录上自己的账户,给你跳转到一个新的页面上,这时候便是守卫起了作用,

导航守卫对路径进行了一个判断,如果此刻我们已经登录上了自己的账户,则会跳转到下一个界面,否则会继续登录

(2)全局前置守卫:

router.beforeEach 注册一个全局前置守卫:

const router = createRouter({ ... })

router.beforeEach((to, from) => {
  // ...
  // 返回 false 以取消导航
  return false
})

当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中

每个守卫方法接收两个参数:

可以返回的值如下:

  • false: 取消当前的导航。如果浏览器的 URL 改变了(可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
  • 一个路由地址: 通过一个路由地址跳转到一个不同的地址,就像你调用 router.push() 一样,你可以设置诸如 replace: truename: 'home' 之类的配置。当前的导航被中断,然后进行一个新的导航,就和 from 一样。

如果遇到了意料之外的情况,可能会抛出一个 Error。这会取消导航并且调用 router.onError() 注册过的回调。

如果什么都没有,undefined 或返回 true则导航是有效的,并调用下一个导航守卫

(3)路由独享守卫:

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

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]

beforeEnter 守卫 只在进入路由时触发,不会在 paramsqueryhash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。

(4)组件内部守卫:

可以在路由组件内直接定义路由导航守卫(传递给路由配置的):

const UserDetails = {
  template: `...`,
  beforeRouteEnter(to, from) {
    // 在渲染该组件的对应路由被验证前调用
    // 不能获取组件实例 `this` !
    // 因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    // 在当前路由改变,但是该组件被复用时调用
    // 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
    // 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
    // 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
    // 在导航离开渲染该组件的对应路由时调用
    // 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
}

5.总结

本文在参考了大量前辈的文章与官方文档后写出,可能会有很多重复的地方,自己对router的理解也不够深入,如果需要了解详情,还是请去查看官方的文档