一、路由概念和原理
后端路由: 请求方式、请求地址与 function 处理函数之间的对应关系
const express = require('express')
const router = express.Router()
router.get('/userlist',function(req,res){/*路由处理函数*/})
router.post('/adduser',function(req,res){/*路由处理函数*/})
module.exports = router
前端路由: 实现不同功能之间的切换,Hash 地址与组件之间的对应关系。
前端路由的工作方式
① 用户点击了页面上的路由链接
② 导致了 URL 地址栏中的 Hash 值发生了变化
③ 前端路由监听了到 Hash 地址的变化
④ 前端路由把当前 Hash 地址对应的组件渲染都浏览器中
实现简易的前端路由
1. 导入并注册 MyHome、MyMovie、MyAbout 三个组件
import MyHome from './components/MyHome.vue'
import MyMovie from './components/MyMovie.vue'
import MyAbout from './components/MyAbout.vue'
export default{
components:{
MyHome,
MyMovie,
MyAbout,
}
}
2. 通过 <component> 标签的 is 属性,动态切换要显示的组件
<template>
<h1>App 组件</h1>
<component :is="comName"></component>
</template>
export default{
data() {
return {
comName: 'my-home', //要展示的组件的名称
}
}
}
3. 在组件的结构中声明如下 3 个 <a> 链接,通过点击不同的 <a> 链接,切换浏览器地址栏中的 Hash 值。
<a href="#/home">Home</a>
<a href="#/movie">Movie</a>
<a href="#/about">About</a>
4. 在 created 生命周期函数中监听浏览器地址栏中 Hash 地址的变化,动态切换要展示的组件的名称
created(){
window.onhashchange = () => {
switch(location.hash) {
case: '#/home':
this.comName = 'my-home'
break
case: '#/movie':
this.comName = 'my-movie'
break
case: '#/about':
this.comName = 'my-about'
break
}
}
}
二、vue-router 的基本使用
在项目中安装 vue-router(vue3 的项目中只能用 vue-router 4.x)
npm install vue-router@next -S
定义路由组件
<template>
<h3>组件</h3>
</template>
<script>
export default{
name:'MyAbout',
}
</script>
<style>
</style>
声明路由链接<router-link> 和占位符<router-view>
<template>
<h1>组件</h1>
<!--声明路由链接-->
<router-link to="/home">首页</router-link>
<router-link to="/movie">首页</router-link>
<router-link to="/about">首页</router-link>
<!--声明路由占位符-->
<router-view></router-view>
</template>
创建路由模块
- 从 vue-router 中按需导入两个方法
- 导入需要使用路由控制的组件
- 创建路由实例对象
- 向外共享路由实例对象
- 在 main.js 中导入并挂载路由模块
从 vue-router 中按需导入两个方法
//createRouter用于创建路由的实例对象
//createWebHashHistory 用于指定路由的工作模式(hash模式)
import { createRouter, createWebHashHistory } from 'vue-router'
导入需要使用路由控制的组件
import Home from './components/MyHome.vue'
import Movie from './components/MyMovie.vue'
import About from './components/MyAbout.vue'
创建路由实例对象
const router = createRouter({
history: createWebHashHistory(),
routes:[
{ path: '/home',component:Home },
{ path: '/movie',component:Movie },
{ path: '/about',component:About },
],
})
向外共享路由实例对象
export default router
在 main.js 中导入并挂载路由模块
import { createApp } from 'vue'
import App from './App.vue'
import './index.css'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')
三、vue-router 的高级用法
1. 路由重定向
用户在访问地址 A 的时候,强制用户跳转到地址 C ,从而展示特定的组件页面。
通过路由规则的 redirect 属性,指定一个新的路由地址,可以很方便地设置路由的重定向:
const router = createRouter({
history:createWebHashHistory(),
routes:[
{ path:'/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About },
]
})
2. 路由高亮
默认的高亮 class 类
被激活的路由链接,默认会应用一个叫做 router-link-active 的类名:
.router-link-active{
background-color:red;
color:white;
font-weight:bold;
}
自定义路由高亮的 class 类
linkActiveClass 属性,自定义路由链接被激活时所应用的类名:
const router = createRouter({
history:createWebHashHistory(),
linkActiveClass: 'router-active',
routes:[
{ path:'/', redirect: '/home' },
{ path: '/home', component: Home },
{ path: '/movie', component: Movie },
{ path: '/about', component: About },
]
})
3. 嵌套路由
通过路由实现组件的嵌套展示
- 声明子路由链接和子路由占位符
<template>
<h1>MyAbout组件</h1>
<!--声明子路由链接-->
<router-link to="/about/tab1">首页</router-link>
<router-link to="/about/tab2">首页</router-link>
<!--声明子路由占位符-->
<router-view></router-view>
</template>
- 通过 children 属性声明子路由规则
在 router.js 路由模块中,导入需要的组件,并使用 children 属性声明子路由规则。
注意:声明子路由时不要加/
import Tab1 from './components/tabs/MyTab1.vue'
import Tab2 from './components/tabs/MyTab2.vue'
const router = createRouter({
routes:[
{
path: '/about',
component: About,
redirect: './about/tab1', //重定向
children:[
{ path: 'tab1', component:Tab1 },
{ path: 'tab2', component:Tab2 },
]
},
]
})
4. 动态路由匹配
把 Hash 地址中可变的部分定义为参数项,从而提高路由规则的复用性。在 vue-router 中
使用英文的冒号(:)来定义路由的参数项。
{ path:'/movie/:id',component:Movie }
可以使用 $route.params 对象访问到动态匹配的参数值。
<template>
<h3>MyMovie组件 --- {{$router.params.id}}</h3>
</template>
<script>
export default{
name: 'MyMovie',
}
</script>
使用 props 接收路由参数
//可在Movie组件中,以props的形式接收到路由规则匹配的参数项
{ path:'/movie/:id',component:Movie, props:true}
<template>
<h3>MyMovie组件 --- {{id}}</h3>
</template>
<script>
export default{
props:['id'],
}
</script>
5. 编程式导航
通过调用 API 实现导航的方式,叫做编程式导航。与之对应的,通过点击链接实现导航的方式,叫做声明式导航。
- 普通网页中点击 <a> 链接、vue 项目中点击 <router-link> 都属于声明式导航
- 普通网页中调用 location.href 跳转到新页面的方式,属于编程式导航
this.$router.push('hash 地址'): 跳转到指定 Hash 地址,从而展示对应的组件
<template>
<h3>MyHome</h3>
<button @click="gotoMovie(3)">go to Movie</button>
</template>
<script>
export default{
methods:{
gotoMovie(id){
this.$router.push('/movie/${id}')
},
},
}
</script>
this.$router.go(数值 n): 实现导航历史的前进、后退
<template>
<h3>MyMovie</h3>
<button @click="goBack">后退</button>
</template>
<script>
export default{
props:['id'],
methods:{
goBack(){ this.$router.go(-1)}
},
}
</script>
6. 命名路由
命名路由的 name 值不能重复,必须保证唯一性!
命名路由实现声明式导航
<template>
<h3>MyHome</h3>
<router-link :to="{ name:'mov', params:{id : 3}}">go to Movie</router-link>
</template>
<script>
export default{
name:'MyHome',
}
</script>
命名路由实现编程式导航
<template>
<h3>MyHome</h3>
<button @click="gotoMovie(3)">go to Movie</button>
</template>
<script>
export default{
methods: {
gotoMovie(id){
this.$router.push({name:'mov',params:{id : 3}})
},
},
}
</script>
7. 导航守卫
全局导航守卫会拦截每个路由规则,从而对每个路由进行访问权限的控制。
const router = createRouter({...})
//每次拦截到路由的请求都会用fn处理
router.beforeEach(fn)
全局导航守卫的守卫方法中接收 3 个形参
const router = createRouter({...})
router.beforeEach((to, from, next)=>{
//to目标路由对象
//from当前导航要离开时的路由对象
//next表示放行
})
- 守卫方法中如果不声明 next 形参,则默认允许用户访问每一个路由
- 守卫方法中如果声明了 next 形参,则必须调用 next() 函数,否则不允许用户访问任何一个路由
next函数的3种调用方式
- 直接放行:next()
- 强制其停留在当前页面:next(false)
- 强制其跳转到登录页面:next('/login')
结合 token 控制后台主页的访问权限
router.beforeEach((to, from, next)=>{
const token = localStorage.getItem('token') //读取token
if(to.path === './main' && !token){ //想要访问主页且token不存在
//next(false) //不允许跳转
next('/login') //强制跳到登陆界面
}else{
next() //允许放行
}
})