Skip to content

路由

  • 现实生活中的路由:

生活中的路由

  • Vue中的路由:

    为了完成SPA(single page web application)单页面应用

Vue中的路由

理解

Vue-router

Vue的一个插件库, 专门用来实现SPA应用

SPA 应用

  • 单页面WEB应用(single page web application): SPA
  • 整个应用只有一个完整的页面
  • 点击页面中的导航链接不会刷新页面, 只会做页面的局部更新
  • 数据需要通过AJAX请求获取

路由的理解

路由: 一个路由就是一组映射关系: key-value

  • key: 路由
  • valuefunctioncomponent

路由的分类

后端路由:

  • 理解: valuefunction, 用于处理客户端提交的请求
  • 工作流程: 服务器接收到一个请求时, 根据请求路径找到匹配的函数来处理请求, 返回响应数据

前端路由:

  • 理解: valuecomponent, 用于展示页面
  • 工作流程: 当浏览器的路径改变时, 对应的组件就会展示

路由的基本使用

安装路由

bash
npm i vue-router

创建路由

  • src中新建router文件夹并新建index.js文件用于创建路由
js
// 引入路由
import VueRouter from "vue-router"

// 引入组件
import About from '../components/About.vue'
import Home from '../components/Home.vue'

// 创建路由并导出
export default new VueRouter({
  routes: [
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home
    }
  ]
})

使用路由

  • main.js中引入并使用
js
// 引入 Vue
import Vue from 'Vue'
// 引入根组件 App
import App from './App'
// 引入 VueRouter
import VueRouter from 'vue-router'
import router from './router'
// 使用
Vue.use(VueRouter)

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

切换路由

在组件中实现路由切换, active-class可实现高亮样式

html
<router-link active-class="active" to="/about">About</router-link>
<router-link active-class="active" to="/home">Home</router-link>

展示路由

  • 在组件中指定展示路由的位置
html
<router-view></router-view>

使用路由注意点

注意

  • 路由组件通常存放在pages文件夹中, 一般组件通常存放在components文件夹中
  • 通过切换隐藏了的路由组件, 默认是被销毁掉的, 需要的时候再去重新挂载
  • 每个组件都有自己的$route属性, 存储自己的路由信息
  • 整个应用只有一个router, 可以通过组件的$router属性获取

嵌套(多级)路由

配置路由规则使用children配置项

  • children配置中的path不要加/

  • 跳转要写完整路径: <router-link to="/home/news">News</router-link>

  • 代码示例

js
export default new VueRouter({
  routes: [
    // 一级路由
    {
      path: '/about',
      component: About
    },
    {
      path: '/home',
      component: Home,
      // 二级路由
      children: [
        {
          path: 'news', // 不要写 /news
          component: News
        },
        {
          path: 'message', // 不要写 /message
          component: Message
        }
      ]
    }
  ]
})

路由传参

路由跳转携带参数, 共有两种传参方式:

  1. query传参
  2. params传参

query 传参

  • 跳转传递参数
html
<!-- 字符串写法 -->
<router-link :to="`/home/message/detail?id=${this.id}&name=${this.name}`"></router-link>
<!-- 对象写法 -->
<router-link :to="{
  path: '/home/message/detail',
  query: {
    id: this.id,
    name: this.name
  }
}"></router-link>
  • 接收参数
js
mounted() {
  console.log(this.$route.query.id)
  console.log(this.$route.query.title)
}

params 传参

router配置

注意

使用params传参时, 配置路由匹配规则path中需要拼接/:xxx用于声明接收params

  • 代码示例
js
export default new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
      children: [
        {
          path: 'message',
          component: Message,
          children: [
            {
              name: 'hello', // 给路由命名
              path: 'details/:id/:title', // 使用占位符声明接收 params 参数
              component: Details
            }
          ]
        }
      ]
    }
  ]
})

跳转传递参数

注意

params传参的对象写法只能使用name跳转, 不能使用path跳转

  • 代码示例
html
<!-- 字符串写法 -->
<router-link :to="`/home/message/detail/${this.id}/${this.name}`"></router-link>
<!-- 对象写法 -->
<router-link :to="{
  <!-- path: '/home/message/detail', -->
  name: 'hello',
  params: {
    id: this.id,
    name: this.name
  }
}"></router-link>
  • 接收参数
js
mounted() {
  console.log(this.$route.params.id)
  console.log(this.$route.params.title)
}

命名路由

作用: 可以简化路由的跳转

使用:

  • 在配置项中添加name属性:
js
export default new VueRouter({
  routes: [
    {
      path: '/home',
      component: Home,
      children: [
        {
          path: 'message',
          component: Message,
          children: [
            {
              name: 'hello', // 给路由命名
              path: 'details',
              component: Details
            }
          ]
        }
      ]
    }
  ]
})

简化跳转: router-link标签的属性to为对象时才可根据name进行跳转

  • 代码示例
html
<!-- 简化前: 需写完整的路径 -->
<router-link to="/home/message/details">跳转</router-link>
<!-- 简化后: 直接使用路由的命名跳转 -->
<router-link :to="{ name: 'hello' }">跳转</router-link>
<!-- 简化写法配合 query 传参 -->
<router-link :to="{
  name: 'hello',
  query: {
    id: 1,
    name: 'world'
  }
}">跳转</router-link>

路由的 props 配置

作用: 让路由组件更方便的接收到参数

router 配置 props

共有三种写法:

第一种:

props值为对象, 该对象中所有的key: value键值对的组合都可以在组件中通过props接收

  • 代码示例
js
{
  name: 'index',
  path: '/home',
  component: Home,
  props: {
    id: '001',
    name: 'Hello World'
  }
}

第二种:

props值为布尔值, 当布尔值为真时, 此组件收到的所有params参数都可以在组件中通过props接收

注意

只有params跳转传参时可以接收, query传参无法接收

  • 代码示例
js
{
  name: 'index',
  path: '/home',
  component: Home,
  props: true
}

第三种:

props值为函数, 函数形参中会携带当前的route数据, 该函数返回一个对象, 对象中的key: value都可以在组件中通过props接收

备注

可通过解构赋值简写

  • 代码示例
js
{
  name: 'index',
  path: '/home',
  component: Home,
  props($route) {
    return {
      id: $route.query.id,
      name: $route.query.name
    }
  }
  // 简写1: 解构
  props({query}) {
    return {
      id: query.id,
      name: query.name
    }
  }
  // 简写2: 连续解构
  props({query: {id, name}}) {
    return {
      id,
      name
    }
  }
}

组件接收 router 配置的 props

跟组件通信的props接收方法相同

  • 代码示例
js
export default {
  props: ['id', 'name'],
  mounted() {
    console.log(this.id)
    console.log(this.name)
  }
}

作用: 控制路由跳转时操作浏览器历史记录的模式

浏览器的历史记录有两种写入方式:

  1. push: 追加历史记录, 默认为push方式, 浏览器中可以后退
  2. replace: 替换当前记录
  • 开启replace模式
html
<route-link :replace="true" to="/home/message/details">跳转</route-link>
<route-link replace to="/home/message/details">跳转</route-link>

编程式路由

作用: 不借助<router-link>实现路由跳转, 让路由跳转更加灵活

  • 代码示例:
js
this.$router.push({
  name: 'hello',
  query: {
    id: m.id,
    title: m.title
  }
})

this.$router.replace({
  name: 'hello',
  query: {
    id: m.id,
    title: m.title
  }
})

前进: this.$router.back()

后退: this.$router.forward()

指定页面栈数量前进或后退: this.$router.go(-2)表示后退两个页面

缓存路由组件 keep-alive

作用: 让不展示的路由组件保持挂载, 不被销毁

使用: 使用<keep-alive></keep-alive>包裹要缓存路由组件的router-view标签

include: 指定要缓存的路由组件, 填写的是组件名称, 不配置将缓存该router-view的所有组件, 指定缓存多个时写成数组

  • 代码示例:
html
<!-- 指定缓存单个组件 -->
<keep-alive include="News">
  <router-view></router-view>
</keep-alive>
<!-- 指定缓存多个组件 -->
<keep-alive :include="['News', 'Hello', 'Home']">
  <router-view></router-view>
</keep-alive>

两个新的生命周期函数-路由组件

作用: 路由组件所独有的两个钩子, 用于捕获路由组件的激活状态

当路由组件被keep-alive缓存时, mountedbeforeDestroy等生命周期便无法监视到, 如果需要在组件不展示的时候清除定时器等一系列操作时, 可使用这两个生命周期出来相关业务逻辑

  • activated: 路由组件被激活时触发
  • deactivated: 路由组件失活时触发

路由守卫

作用: 对路由进行权限限制, 保护路由的安全

分类:

  • 全局守卫
  • 独享守卫
  • 组件内守卫

全局守卫

全局路由守卫共有两个方法:

  • beforeEach(to, from, next): 全局前置路由守卫, 初始化时及每次路由切换之前被调用

    • to: 将要跳转的路由信息
    • from: 上一个路由信息
    • next: 是否放行
  • afterEach(to, from): 全局后置路由守卫, 初始化时及每次路由切换之后被调用

    • to: 跳转的路由信息
    • from: 上一个路由信息
  • 代码示例

js
// 全局前置路由守卫 => 初始化时 及 每次路由切换之前被调用
router.beforeEach((to, from, next) => {
  console.log('全局前置路由守卫', to, from)
  to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
})

// 全局后置路由守卫 => 初始化时 及 每次路由切换之后被调用
router.afterEach((to, from) => {
  console.log('全局后置路由守卫', to, from)
  // 前置路由守卫放行后修改页面的标题
  document.title = to.meta.title || 'test'
})

独享守卫

某一个路由所独享的路由守卫, 只有一个方法:

  • beforeEnter(to, from, next)

  • 注意, 没有afterEnter方法

  • meta是路由元信息

  • 代码示例

js
{
  name: 'homeName',
  path: '/home',
  component: Home,
  meta: {
    title: '主页'
  },
  beforeEnter: (to, from, next) => {
    to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
  }
}

组件内守卫

组件内部的路由守卫, 共有两个方法:

  1. beforeRouterEnter(to, from, next): 通过路由规则, 进入该组件时调用
  2. beforeRouterLeave(to, from, next): 通过路由规则, 离开该组件时调用
  • 代码示例
js
export default {
  name: 'Demo',
  // 通过路由规则, 进入该组件时调用
  beforeRouteEnter (to, from, next) {
    console.log('About----beforeRouteEnter', to, from)
    to.meta.isAuth ? localStorage.getItem('user') === '9ml' ? next() : alert('当前账户无权限') : next()
  },
  // 通过路由规则, 离开该组件时调用
  beforeRouteLeave (to, from, next) {
    console.log('About----beforeRouteLeave', to, from)
    next()
  }
}

hash 模式与 history 模式

路由器的两种工作模式

哈希值: 网页地址#及其后面的内容就是hash值, hash值不会包含在HTTP请求中, 即: hash值不会带给服务器

hash 模式

  • 地址中永远带着#, 不美观
  • 若以后将地址通过第三方手机App分享, 若app校验严格, 则地址会被标记为不合法
  • 兼容性好

history 模式

  • 地址干净, 美观
  • 兼容性和hash模式相比略差
  • 应用部署上线时需要后端人员支持, 解决刷新页面服务器404的问题
  • node中借助connect-history-api-fallback解决history模式页面刷新请求服务器问题