Vue「六」前端路由、vue-router

Vue 系列笔记第六篇。本文参考:>> 黑马程序员 Vue 全套视频教程

系列文章阅读

>> Vue「一」—— 前端工程化 、webpack 的基本使用及常用配置

>> Vue「二」—— vue 基本使用 、vue 指令 、vue 过滤器

>> Vue「三」—— vue 侦听器、vue 计算属性、vue-cli、vue 组件

>> Vue「四」—— 组件生命周期、数据共享

>> Vue「五」—— 动态组件、插槽、自定义指令

>> Vue「六」—— 前端路由、vue-router

文章内容预览

  • 一、前端路由的概念与原理
  • 二、vue-router 的基本使用
  • 三、vue-router 的常见用法
    • 1. 路由重定向
    • 2. 嵌套路由
    • 3. 动态路由匹配
    • 4. 声明式导航 & 编程式导航
    • 5. 导航守卫

一、前端路由的概念与原理


首先,什么是路由?

路由的概念来源于服务端,在服务端中路由描述的是 URL 与处理函数之间的映射关系。简单来说,路由指的就是针对不同请求的 URL,处理不同的业务逻辑。

而什么又是前端路由?

历史由来就不讲了,热榜文章都有,直接来点干货。

如今热门的单页面应用程序 SPA 中,不同页面间的切换、数据交互是无刷新的,不会每次都发起服务器请求,减少了与服务器请求和响应时间,极大提高了用户体验。

页面间无刷新切换是靠什么实现的呢?那就是 前端路由

看看下面这个简陋版的后台管理系统案例,这就是一个单页面应用程序。尽管页面进行了多次切换,但是页面并没有进行重载,或者说的准确点,没有向服务器提交请求获取新页面,仅仅是完成了不同组件间的切换。

那前端路由起到了什么作用呢,可以看到在页面切换时,变换的只有 localhost:8080/ 后面的部分,这部分我们姑且称之为 Hash 地址,可利用 window.location.hash 来获取。在这里,前端路由就是不同 Hash 地址与不同组件的对应关系,根据路由对应关系来完成不同组件之间的切换。
Vue「六」前端路由、vue-router_第1张图片

而要弄懂为什么没有发起服务器请求,你首先要明白 hash (#)的机理

最重要一点,HTTP 请求不包括 hash

比如,你要访问 http://localhost:8080/#/login ,但是实际上浏览器发出的请求是:
Vue「六」前端路由、vue-router_第2张图片
这也就意味着,当页面 Hash 地址变化时,并不会引起浏览器发出服务器请求。

这部分存在的意义仅仅是用来指导浏览器行为的,比如说当 Hash 地址为 #/login 时,浏览器就在指定位置显示登录组件。

还有一点,改变 hash 会增加浏览器访问历史

根据这一点,我们就可以实现根据访问历史前进后退。例如,利用 API $router.back() 可以实现后退到前一个页面的效果。

 
前端路由的工作方式

① 用户点击了页面上的路由链接,导致了 URL 地址栏中的 Hash 值发生了变化;

前端路由监听了到 Hash 地址的变化

③ 前端路由把当前 Hash 地址对应的组件 渲染都浏览器中。

如,举例链接、前端路由以及组件关系:
Vue「六」前端路由、vue-router_第3张图片

这种意义上来说,前端路由就是 Hash 地址与组件之间的对应关系

 
那么,怎么创建前端路由呢 ?我们来手动模拟一下。
Vue「六」前端路由、vue-router_第4张图片
给定三个链接,首页、电影、关于,点击对应链接,则在页面中动态渲染出对应组件。

<template>
  <div class="app-container">
    <h1>App 根组件h1>

    <a href="#/home">首页a>
    <a href="#/movie">电影a>
    <a href="#/about">关于a>
    <hr />
    <component :is="comName">component>
  div>
template>

我们怎么操作呢?首先要绑定事件 window.onhashchange 当前页面 Hash 值变化时触发,再利用 location.hash 获取 Hash 值。根据获取的不同 Hash 值来给动态组件指定名称。

  data() {
    return {
      comName: "Home"
    }
  },
  created() {
    window.onhashchange = () => {
      switch (location.hash) {
        case "#/home":
          this.comName = "Home"
          break
        case "#/movie":
          this.comName = "Movie"
          break
        case "#/about":
          this.comName = "About"
          break
      }
    }
  },

但是,在实际中我们并不会去手动配置前端,而是去利用一些第三方库,如下面即将介绍的 vue-router
 

二、vue-router 的基本使用


vue-router 是 vue.js 官方给出的 路由解决方案 。它只能结合 vue 项目进行使用,能够轻松的管理 SPA 项目中组件的切换。

官方文档:https://router.vuejs.org/zh/

使用 vue-router 的五部曲

① 安装 vue-router 包

② 创建路由模块

③ 导入并挂载路由模块

④ 声明路由链接和占位符

⑤ 声明路由的匹配规则

1. 安装 vue-router 包

npm install vue-router

2. 创建路由模块

src 源代码目录下,新建 router/index.js 路由模块,并初始化如下的代码:

import Vue from 'vue'
import VueRouter from 'vue-router'

// 调用 Vue.use 函数,把 VueRouter 安装为 Vue 插件
Vue.use(VueRouter)
// 创建路由的实例
const router = new VueRouter()
// 向外共享路由的实例对象
export default router

3. 导入并挂载路由模块

如果想在 Vue 项目中使用路由,就必须在 src/main.js 入口文件中,导入并挂载路由实例。

import Vue from 'vue'
import App from './App.vue'

// 导入路由模块,拿到路由的实例对象
import router from '@/router/index.js'

new Vue({
  render: h => h(App),
  // 路由实例对象
  // 简写 router: router
  router
}).$mount('#app')

4. 声明路由链接和占位符

src/App.vue 组件中,使用 vue-router 提供的 声明路由链接和占位符。

<template>
  <div class="app-container">
    
    <router-link to="/home">首页router-link>
    <router-link to="/movie">电影router-link>
    <router-link to="/about">关于router-link>
    
    <router-view>router-view>
  div>
template>

5. 声明路由的匹配规则

src/router/index.js 路由模块中,通过 routes 数组 声明路由的匹配规则。

const router = new VueRouter({
    // 定义 Hash 与组件之间的对应关系
    // 路由规则
    routes: [
        { path: '/home', component: Home },
        { path: '/movie', component: Movie },
        { path: '/about', component: About },
    ]
})

这样就实现前端路由的配置:
Vue「六」前端路由、vue-router_第5张图片
 

三、vue-router 的常见用法


1. 路由重定向


路由重定向 指的是:用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面。
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向。

const router = new VueRouter({
    routes: [
        // 当访问 / 时,通过 redirect 属性直接跳转到 /home 对应的路由规则
        { path: '/', redirect: '/home' },
        // 路由规则
        { path: '/home', component: Home },
        { path: '/movie', component: Movie },
        { path: '/about', component: About },
    ]
})

这样可以使得,在开始打开页面时不至于显示空白,而是直接跳转到 home 首页。
 

2. 嵌套路由


通过路由实现组件的嵌套展示,叫做 嵌套路由 。也就是在由路由显示的组件中,还有含有路由可以显示再下一层的组件,即大家常说的套娃。

Vue「六」前端路由、vue-router_第6张图片

> 声明子路由链接和子路由占位符

如上图,在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符,可以这样操作:

<template>
  <div class="about-container">
    <h3>About 组件h3>
    
    <router-link to="/about/tab1">tab1router-link>
    <router-link to="/about/tab2">tab2router-link>
    <hr />
    
    <router-view>router-view>
  div>
template>

仅仅是声明子路由链接和占位符还不算完,还要引入 子路由规则

> 通过 children 属性声明子路由规则

src/router/index.js 路由模块中,导入需要的组件,并使用 children 属性 声明子路由规则:

const router = new VueRouter({
    routes: [
        {
            path: '/about',		// 声明父级路由规则
            component: About,
            children: [         // 嵌套声明子路由规则
                { path: 'tab1', component: Tab1 },      // about/tab1
                { path: 'tab2', component: Tab2 }       // about/tab2
            ]
        }
    ]
})

> 默认子路由

当打开 About 组件时,可以直接显示出某个子路由,而不是不做显示。这时,除了设置路由重定向 redirect 属性,也可以通过 默认子路由 来解决。默认子路由具体为,如果在 children 数组中某个路由规则 path: '' ,则称该路由规则为默认子路由。

    children: [         
        { path: '', component: Tab1 },          // 默认显示 Tab1
        { path: 'tab2', component: Tab2 }       // about/tab2
    ]

 

3. 动态路由匹配


如果我们有这样一个需求,点击下面的链接,都会跳转到 Movie 组件,哪么怎么办?你要一条条配置路由规则嘛?这里只是给出了 3 个链接,如果是 300 个、3000 个呢?当然不是逐条配置路由规则,我们可以使用 动态路由匹配

	
    <router-link to="/movie/1">教父三部曲router-link>
    <router-link to="/movie/2">闻香识女人router-link>
    <router-link to="/movie/3">西西里的美丽传说router-link>

动态路由指的是,把 Hash 地址中可变的部分定义为 参数项 ,从而提高路由规则的复用性。

在 vue-router 中,可以使用英文的冒号 : 来定义路由的参数项。这样就避免了逐条配置的麻烦。

	{ path: '/movie/:id', component: Movie },

> $route.params 参数对象

如果除此之外,我们还想获得该参数项具体参数值(如 ".movie/1" 后面参数值 1),根据这个参数值展示相应的内容,应该怎么办?

在动态路由渲染出来的组件中,可以通过 this.$route 访问路由的参数对象:
Vue「六」前端路由、vue-router_第7张图片
可以看到,其中 this.$route.params 中包含有我们需要的参数值 id ,获取该 id 即可。

这种获取参数值的方式是比较传统方式,比较复杂,不是很推荐。可以使用下面开始 props 来进行传参。

> 使用 props 接收路由参数

为了简化路由参数的获取形式,vue-router 允许在路由规则中 开启 props 传参

在创建实例时,开启 props 传参:

const router = new VueRouter({
    routes: [
        { path: '/movie/:id', component: Movie, props: true },		// 开启 props 传参
    ]
})

在 Movie 组件中通过 props 接收参数:

export default {
  name: "Movie",
  props: ["id"],	// 接收路由规则中的匹配到的参数
}

 

4. 声明式导航 & 编程式导航


  • 声明式导航

在浏览器中,点击链接 实现导航的方式,叫做 声明式导航

例如:普通网页中 链接 、vue 项目中的 都属于声明式导航。

  • 编程式导航

在浏览器中,调用 API 方法 实现导航的方式,叫做 编程式导航

例如:普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航。

> vue-router 中编程式导航 API

vue-router 提供了许多编程式导航的 API,其中最常用的导航 API 分别是:

API 描述
this.$router.push('hash 地址') 跳转到指定 hash 地址,并 增加 一条记录
this.$router.replace('hash 地址') 跳转到指定 hash 地址,并且 替换 当前历史记录
this.$router.go(n) 实现浏览历史前进后退,如 n=-1 退回前一个页面
this.$router.back() 在历史记录中,后退到上一个页面
this.$router.forward() 在历史记录中,前进到下一个页面
<button @click="$router.back()">后退button>

 

5. 导航守卫


导航守卫 可以控制路由的访问权限。可以参考此图:
Vue「六」前端路由、vue-router_第8张图片
> 全局前置守卫

每次发生路由的 导航跳转 时,都会触发全局前置守卫。因此,在全局前置守卫中,程序员可以对每个路由进行 访问权限 控制。

怎么创建全局前置守卫呢 ?这需要我们在创建路由实例时进行定义函数 router.beforeEach,如下:

// 创建路由的实例
const router = new VueRouter({...})

// 声明全局前置导航守卫
router.beforeEach((to, from, next) => {
	// to 表示将要访问的路由的信息对象
	// from 表示将要离开的路由的信息对象
	// next 是函数,调用 next 表示允许此次导航
})

这里的 next 函数有如下三种调用方式:

  1. 直接放行:next()
  2. 强制跳转:如 next('/login') 跳转至登录页面
  3. 不允许跳转,停留在当前页面:next(false)

参考下图来理解一下这三种调用方式:
Vue「六」前端路由、vue-router_第9张图片
例如,可以通过下面这段代码来控制后台访问权限

// 声明全局前置导航守卫
router.beforeEach((to, from, next) => {
    if (to.path === "/main") {
        // 判断是否有 token,没有 token 则转登录页面
        const token = localStorage.getItem("token")
        token ? next() : next("/login")
    }
    else    // 没有访问后台页面,直接放行
        next()
})

你可能感兴趣的:(Vue,vue.js,前端路由,vue-router)