繁星永存 记忆亘古不变

前端路由

前端路由,指的是 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 },
]

声明式导航

  • 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():获取一个包含所有路由记录的数组。

评论



本站使用 Volantis 主题设计

:doodle { @grid: 1x5 / 100vmin; } @place-cell: center; width: @rand(45vmin, 75vmin); height: @rand(45vmin, 75vmin); transform: translate(@rand(-120%, 120%), @rand(-80%, 80%)) scale(@rand(.8, 2.8)) skew(@rand(45deg)); clip-path: polygon( @r(0, 30%) @r(0, 50%), @r(30%, 60%) @r(0%, 30%), @r(60%, 100%) @r(0%, 50%), @r(60%, 100%) @r(50%, 100%), @r(30%, 60%) @r(60%, 100%), @r(0, 30%) @r(60%, 100%) ); background: @pick(#f44336, #9c27b0, #673ab7, #3f51b5, #60569e, #e6437d, #ebbf4d, #00bcd4, #03a9f4, #2196f3, #009688, #5ee463, #f8e645, #ffc107, #ff5722, #43f8bf, #e136eb, #32ed39); opacity: @rand(.5, .9); position: relative; top: @rand(-80%, 80%); left: @rand(0%, 80%); animation: colorChange @rand(6.1s, 26.1s) infinite @rand(-.5s, -2.5s) linear alternate; @keyframes colorChange { 100% { left: 0; top: 0; filter: hue-rotate(360deg); } }