vue-router
基于Vue做单页面应用时,vue-router可以帮我们将url地址和组件绑定,在我们切换路由组件时,url改变,页面无需从服务端重新加载,即不用刷新,打个比方,我们用美团外卖点外卖时,切换点击左边的菜品标签,若页面总是重新加载,每次重新加载整个页面都闪烁一下,用户的体验很不好。
1. 基本使用
1.1 安装 vue-router:
使用vue2安装对应的router3版本
npm i vue-router@3
使用vue3安装对应的router4版本
npm i vue-router@4
1.2 引入router
在 src 下创建router文件夹,在router文件夹里创建 index.js
/src/router/index.js
//引入Vuerouter
import VueRouter from 'vue-router'
//引入想要展示的路由组件
const router = new VueRouter({
routes:[
{
path: '/xxx',//url
component: [路由组件名],//对应的组件名
},
]
})
export default router
在 main.js 文件中引入并注册路由
main.js
import Vue from 'vue'
import App from './App.vue'
//1. 引入
import VueRouter from 'vue-router'
import router from './router'
Vue.use(VueRouter)
new Vue({
render: h => h(App),
//2. 注册
router
}).$mount('#app')
1.3 使用router
一般在/src/pages下存放路由组件,在/src/components下存放其他组件
1.3.1 路由导航 <router-link>
<router-link> 用来导航显示想展示的组件,本质上就是个超链接标签<a>,有如下属性
:to=“/xxx” --> 去展示对应url对应的组件
active-class=“[class名]” --> 当导航被激活时想展示的class样式
replace --> 切换路由时替换当前浏览器的历史记录
push --> 默认为push,再切换路由时追加浏览器历史记录
1.3.2 路由组件展示<router-view>
<router-view>用于把选择了<router-link>对应的组件展示到<router-view>放置的位置
1.4 简单的路由例子
下方的例子就是一个简单的路由,如果导航被激活,就会显示如图的红色,并在下方展示子组件数据
App.vue
<template>
<div id="app">
<ul>
<li v-for="(item,index) in list"
:key="item.id">
<router-link
active-class="router-active"
:to="item.path">
{{ item.name }
</router-link>
</li>
</ul>
<router-view/>
</div>
</template>
<script>
export default {
name: 'App',
data() {
return {
list: [
{ id: 2, name: '人员', path: '/persons'},
{ id: 3, name: '新闻', path: '/news' }
],
}
}
}
</script>
<style scoped>
* {
margin: 0;
padding: 0;
}
#app ul {
display: flex;
padding: 0 10px;
}
#app ul li {
width: 100px;
height: 50px;
line-height: 50px;
list-style: none;
text-align: center;
border: 1px solid black;
}
#app ul li a {
display: block;
text-decoration: none;
font-weight: bold;
color: #333333;
}
.router-active{
background-color: #e01222;
color: #fff;
}
</style>
/router/index.js
import VueRouter from "vue-router"
//引入想要用的组件
import PersonList from "@/pages/PersonList.vue"
import News from "@/pages/News.vue"
const router = new VueRouter({
routes: [
{
path: '/persons',
component: PersonList
},
{
path: '/news',
component: News
}
]
})
export default router
/pages/News.vue
<template>
<div>
<h3>新闻列表</h3>
<li v-for="item in NewsList" :key="item.id">
{{item.title}}
</li>
</div>
</template>
<script>
export default{
name: '',
data(){
return{
NewsList: [
{id:'001',title:'新闻1', path: '/new'},
{id:'002',title:'新闻2', path: '/new'},
{id:'003',title:'新闻3', path: '/new'},
]
}
},
}
</script>
/pages/PersonList.vue
<template>
<div>
<ul>
<li v-for="(item) in personList" :key="item.id">
{{item.id}} - {{ item.pName }} - {{ item.age }}
</li>
</ul>
</div>
</template>
<script>
export default{
name: '',
data(){
return{
personList : [
{id:'001',pName:'tom',age:18},
{id:'002',pName:'jerry',age:19},
{id:'003',pName:'tony',age:12},
],
}
}
}
</script>
2. 进阶使用
2.1 多级路由
多级路由是在/router/index.js中routes中的对象中配置children属性,在children里配置下一级路由的映射规则
import VueRouter from "vue-router"
const router = new VueRouter({
routes: [
{
path: '/xxx',
component: xxx,
//多级路由配置children属性
children: [
{
path: 'yy',//记住不要加/
component: yy
}
]
}
]
})
export default router
此时我们访问到配置的这个子路由的<router-link>的 :to 属性应该写完整的路径,即
<router-link :to="/xxx/yy"></router-link>
2.2 $router 和 $route
$route存放着该组件的路由信息,每个路由组件对象都有$route,可以传递接参数等等
$router是vue路由对象,只会存在一个,可以借助this.$router的api实现编程式路由导航
2.3 路由传参
传参有query传参和param传参两种方式,我们通过在路由组件里的 this.$route.[query / param]获取
二者的字符串写法都支持模板字符串,模版字符串用``围起来,里面可以通过 ${变量名} 获取变量,拼接成字符串
2.3.1 query传参
传递参数都是在<router-link>的 to 属性传递,传递方式有字符串写法和对象写法,获取则是通过 this.$route.query.[变量名]
//1.字符串写法
//传递:在<router-link>的to属性通过url传递,即
to=“/xx?a=a&b=b”
//2. 对象写法
// to="
{
path: '/xx',
query:{
a:a,
b:b
}
}
"
2.3.2 params传参
传递参数都是在<router-link>的 to 属性传递,传递方式有字符串写法和对象写法,获取则是通过 this.$route.params.[变量名]
//1. 字符串写法
to="/xx/a/b"
//这种写法需要在route里匹配路径时占位
// /router/index.js
const router = new VueRouter({
routes: [
{
path: '/xx/:school', // [/:变量名] 实现占位,传多少个参数就占多少位
component: PersonList
}
]
})
//2. 对象写法
//这种写法需要配置route的name属性,见文章2.4 路由取名
// 配置 name 和 params
to="{
name: [路由name属性名,即aa],
params: {
a : a,
b : b
}
}"
// /router/index.js
// 注意 name、path
const router = new VueRouter({
routes: [
{
name: 'aa'
path: 'xx/:a', //占位
component: PersonList
}
]
})
2.4 路由取名
我们可以给路由取名,通过 to=“[路由名]” 即可访问
const router = {
routes: [
{
//取名
name: 'aaa',
path: '/xxx',
component: xxx,
//多级路由配置children属性
children: [
{
path: 'yy',//记住不要加/
component: yy
}
]
}
]
}
//访问
<router-link :to="aaa"></router-link>
2.5 缓存路由
我们在切换同级路由时,切换走的路由组件会被销毁,切换到的路由组件会被创建,有时候我们希望切换组件时,保留该组件现有的数据,即不销毁掉该路由组件,这就是缓存路由
缓存路由通过<keep-alive>标签的include属性控制,如果想缓存多个路由,则用 :include=“[‘a组件’, ‘b组件’]”,需要在组件里配置name属性,若没配置include则所有都缓存
<keep-alive :include="['xx']">
<router-view></router-view>
</keep-alive>
2.6 路由组件的生命周期函数
引入: 一个路由组件有定时器,并且keep-alive 了,我们不希望定时器在切换的时候依旧执行
解决上述问题,我们可以通过路由组件的activated、deactivated 两个生命周期函数,在路由组件激活时开始,路由切换时关闭即可,这两个生命周期函数仅在<keep-alive>包含当前组件时才会有
activated 路由组件被激活时激活
deactivated 路由组件被切换的时候激活
2.7 路由守卫
引入 : 有些路由组件需要判断权限,没权限就不给看
2.7.1 全局前置路由守卫
配置在 /router/index.js 里,路由组件的初始化和每次切换时调用
一般用于权限控制
/router/index.js
// to : 目标路由
// from : 从哪个路由切换的,是一个Object对象
// next : 要切换到哪个路由,是一个Object对象
router.beforeEach((to, from, next) -> {
//权限验证
next(); //放行
})
2.7.2 全局后置路由守卫
配置在 /router/index.js 里,路由组件的初始化和每次切换后调用
/router/index.js
// to : 目标路由,是一个Object对象
// from : 从哪个路由切换的,是一个Object对象
//由于是在路由器切换后调用的,所以不需要 next
router.afterEach((to, from) -> {
})
2.7.3 独享前置路由守卫
只有前置,没有后置,配置在 /router/index.js 里,存在该独享前置路由守卫的路由组件被激活时触发
/router/index.js
routes = new VueRouter({
{
path: '/xx',
beforeEnter:(to, from, next) => {
next();//放行
}
})
2.7.4 组件内路由守卫
配置在路由组件里
beforeRouteEnter() 在切换到该路由组件时调用
beforeRouteLeave() 在离开该路由组件时前调用
//通过路由规则进入时调用
beforeRouteEnter(to, from, next) {
next(); //放行
}
//通过路由规则离开前调用
beforeRouteLeave(to, from, next) {
next(); //放行
}
2.7.5 路由守卫的执行顺序
如果各种守卫都配置了,
路由组件初始化时,触发顺序如下:
全局前置路由守卫 -> 全局后置路由守卫
组件被激活时,触发顺序如下:
全局前置路由守卫 -> 独享前置路由守卫 -> 组件内路由前置守卫 -> 全局后置路由守卫
组件被切换走时,触发顺序如下:
组件内路由离开守卫 -> 全局前置路由守卫 -> 全局后置路由守卫
2.8 路由器的工作模式
工作模式通过router的mode属性配置,有history 和 hash 两种,默认是hash
hash : 只有#之前的url会随着请求会发给服务器,不会带上路由组件的url
history : 会把我们配置的路由组件的url也带上
打个比方:
// 我们想请求的地址 : https://localhost:8080/students
// 此时,我们在路由组件Person准备发送请求,即此时的url为: https://localhost:8080/#/person
// 我们发送 /students 的请求
// history : https://localhost:8080/person/students
// hash : https://localhost:8080/person
// 此时,history当前请求不到资源
修改路由的工作模式如下:
const router = new VueRouter({
mode: ['hash' / 'history'],
routes: [
]
})