前端路由

前端路由,指的是 Hash 地址与组件之间的对应关系

工作方式:

  1. 用户点击了页面的路由链接
  2. 导致了 URL 地址栏的 Hash 值方式变化
  3. 前端路由监听到 Hash 地址的变化
  4. 前端路由把当前 Hash 值地址对应的组件渲染到浏览器页面

简单路由的实现

<!-- a 链接添加对应的 hash 值 -->
<a href="#/home">Home</a>
<a href="#/movie">Movie</a>
<a href="#/about">About</a>
<!-- 动态渲染结点 -->
<!-- 通过 is 属性 指定要展示的组件 -->
<comnponent :is="comName"></comnponent>
<script>
export default{
  name:'App',
  data(){
    return{
      comName:'Home'
    }
  },
  // 在 created 生命周期函数中,监听浏览器地址栏中hash 地址的变化
 //动态切换要展示的组件的名称
  created(){
    window.onhashchange=()=>{
      switch(location.hash){
        case: '#/home':
          this.comName = 'Home'
          break
     case: '#/movie':
          this.comName = 'Movie'
          break
        case: '#/about':
          this.comName = 'About'
          break
      }
    }
  }
}
</script>

vue-router

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

vue-router 的官方文档地址

基本用法

1.安装:在 vue2 的项目中,安装 vue-router@3.5.2

npm i vue-router@3.5.2 -S

2.在项目 src目录下 新建 router/index.js 路由模块

// 导入 vue 和 vue-router
import Vue from 'vue'
import VueRouter from 'vue-router'

// 调用 Vue.app() 安装 VueRouter
Vue.app(VueRouter)

// 创建路由实例对象
const router = new VueRouter()

// 导出共享
export default router

3.导入挂载,在 src/main.js 入口文件导入挂载路由模块

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

// 1.导入
import router from './router/index.js'

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

4.声明路由链接和占位符 在 App.vue 里使用 vue-router 提供的 <router-link>router-view 声明路由链接和占位符

<template>
 <div>
    <h1> App组件 </h1>
    
    <!-- 定义路由链接 -->
    <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,通过 routers 数组声明匹配规则

// 导入 需要使用路由切换的组件
import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '@/component/Home.vue'
import About from '@/component/About.vue'
import Movie from '@/component/Movie.vue'

// 创建路由实例对象
const router = new VueRouter({
// 路由匹配规则
  routes
})
 const routes = [
  // path 表示匹配的 hash 地址
  // component 表示要展示的组件
  { path: '/home', component: Home },
  { path: '/about', component: About },
  { path: '/movie', component: Movie },
]

声明式导航

<router-link> 的基本属性

  • to

    一个字符串,或者是一个属性

  • replace

    设置 replace 属性的话,当点击时,会调用 router.replace(),而不是 router.push();

  • active-class

    设置激活a元素后应用的class,默认是router-link-active

  • exact-active-class

    链接精准激活时,应用于渲染的 <a> 的 class,默认是router-link-exact-active;

路由重定向

路由重定向指定的是,用户在访问 A 地址,强制用户跳转到 B 地址

const router = new VueRouter({
  routes
})
// 路由匹配规则
  const routes = [
  // 通过 redirect 属性,设置重定向
  // 当用户访问 / 时 跳转到 /home 对应的路由规则
  {path:'/',redirect:'/home'},
  { path: '/home', component: Home },
  { path: '/about', component: About },
  { path: '/movie', component: Movie },
]

嵌套路由

通过路由实现组件的嵌套展示,叫做嵌套路由。

在 About.vue 组件中,声明 tab1 和 tab2 的子路由链接以及子路由占位符

<template>
  <div class="about-container">
    <!-- 要把父路由写上 -->
    <router-link to="/about/tab1">tab1</router-link>
    <router-link to="/about/tab2">tab2</router-link>

    <router-view></router-view>
  </div>
</template>

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

const routes = [
  {
    path: '/about',
    component: 'About',
    children: [
      // 注意不要写成 /tab1
      { path: 'tab1', component: Tab1 },
      { path: 'tab2', component: Tab2 },
    ],
  },
]

动态路由匹配

动态路由指的是:把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。
在 vue-router 中使用英文的冒号(:)来定义路由的参数项。

// 动态参数以 : 进行声明。冒号后面的是动态参数名称
{ path: '/movie/:id', component: Moive },

// 动态路由将下面的规则合成一个提高复用性
{ path: '/movie/1', component: Moive },
{ path: '/movie/2', component: Moive },
{ path: '/movie/3', component: Moive },

参数

动态路由渲染出来的组件中,可以使用 this.$route.params 对象访问到动态匹配的参数值。

<template>
  <div class="about-container">
    <!-- this.$route 是参数对象 -->
    <h3>Movie 组件:接收的参数是{{ this.$route.params }}</h3>
  </div>
</template>

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

// 定义路由规则时 声明 props:true 选项
{ path: '/movie/:id', component: Moive ,props:true},
<template>
  <div class="about-container">
    <!-- 使用 props 中接收的参数 -->
    <h3>Movie 组件:接收的参数是{{ id}}</h3>
  </div>
</template>
<script>
export default{
  // 接收路由规则中匹配的参数项 id
  props:['id']
}
</script>

编程式导航

声明式导航:

  • 通过点击链接实现导航
  • 如普通网页点击 a 链接,vue 点击 <router-link>

编程式导航:

  • 通过调用 API 实现导航
  • 普通网页通过 location.href 的方式跳转页面也是编程式导航

vue-router 中实现编程式导航的 API :

  • this.$router.push('hash地址') :跳转到指定页面,并增加一条历史记录
  • this.$router.replace('hash地址') :跳转页面,但不会新增历史记录,而是替换当前的历史记录
  • this.$router.go(数值) :历史记录前进或后退,相当于点击浏览器前进后退箭头
  • this.$router.forward() :前进一步
  • this.$router.back() :后退一步

导航守卫

导航守卫可以控制路由的访问权限

全局前置守卫

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

// index.js路由模块文件

// 全局前置守卫
router.before({to,from,next}=>{
  // to 将要访问的路由
  // from 将要离开的路由
  // next 是一个函数表示放行
})

next 函数的 3 种调用方式

当前用户拥有后台主页的访问权限,直接放行:next()
当前用户没有后台主页的访问权限,强制其跳转到登录页面:next(‘/login’)
当前用户没有后台主页的访问权限,不允许跳转到后台主页:next(false)

NotFound

对于哪些没有匹配到的路由,我们通常会匹配到固定的某个页面

NotFound的错误页面中,这个时候我们可编写一个动态路由用于匹配所有的页面

{
  path: '/:pathMactch(.*)',
  component: () => improt('../page/NotFound.vue')
}

通过$route.params.pathMatch获取到传入的参数

<h2>
  Not Found: {{ $route.params.pathMatch }}
</h2>

匹配规则后可加*

{
  path: '/:pathMactch(.*)*',
  component: () => improt('../page/NotFound.vue')
}

区别:

image-20221110105621776

动态管理路由

动态添加路由

根据用户不同的权限,注册不同的路由,使用一个方法 addRoute

const categoryRoute = {
  path: '/category',
  component: () => import('../pages/Category.vue')
}
router.addRouter(categoryRoute)

如果添加的路由是一个 children 路由,那么可以传入对应的 name

const homeMomentRoute = {
  // 子路由不用加 / 
  path: 'moment',
  component: () => import('../pages/HomeMoment.vue')
}
router.addRouter('home',homeMomentRoute)

删除路由的三种方式

  • 添加相同 name 的路由

    router.addRoute({
      path: '/about',
      name: 'about',
      component: 'About'
    })
    // 删除之前添加的路由,因为 name 是唯一的
    router.addRoute({
      path: '/other',
      name: 'about',
      component: 'About'
    })
    
  • 通过 removeRoute 方法,传入路由名称

    router.addRoute({
      path: '/about',
      name: 'about',
      component: 'About'
    })
    
    router.removeRoute('about')
    
  • 通过 addRouter 方法返回值回调

    const removeRoute =router.addRoute(routeRecord)
    // 删除路由如果存在
    removeRoute()
    

其他补充方法

  • router.hasRoute():检查路由是否存在。

  • router.getRoutes():获取一个包含所有路由记录的数组。