文章目录
一、基本使用
安装vue-router
Vue2项目:npm i vue-router@3
Vue3项目:npm i vue-router@4
创建router文件夹并在该文件目录下创建index.js用于创建整个应用的全局路由(router)
// 引入VueRouter
import VueRouter from "vue-router";
// 引入pages文件夹下的路由组件
import About from "../pages/About";
import Home from "../pages/Home";
// 创建路由器实例对象router,去管理一组组路由规则
const router = new VueRouter({
// 编写路由规则
routes:[
{
path:'/about', // 地址栏路径为 /about
component:About, // 显示About组件
},
{
path:'/home',
component:Home
},
]
})
// 暴露全局路由router
export default router
main.js中引入路由插件并使用
/* ... */
import VueRouter from 'vue-router' // 引入VueRouter
import router from './router/index' // 引入全局路由
Vue.use(VueRouter) // 使用路由插件
new Vue({
render(createElement) {
return createElement(App);
},
}).$mount('#app')
在父组件App.vue中借助<router-link></router-link>标签实现路由的跳转以及<router-view></router-view>标签指定组件呈现的位置
<template>
<div class="list-group">
<!-- Vue中借助router-link标签实现路由的切换 -->
<router-link class="list-group-item" active-class="active" to="/about"
>About</router-link
>
<router-link class="list-group-item" active-class="active" to="/home"
>Home</router-link
>
<div>
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</div>
</template>
/* ... */
注:<router-link></router-link>中使用to指定路径,使用active-class指定该元素被激活时的样式
二、多级路由
多级路由:使用children配置项配置路由规则:
/* 省略引用 */
export default new VueRouter({
routes:[
{
path:'/about',
component:About,
children:[ // 配置About路由组件的子路由
{
path:'message', // 此处不需要写成'/message'或'/about/message'
component:Message
},
{
path:'news',
component:News
},
]
},
{
path:'/home',
component:Home
},
]
})
此时可通过点击About导航栏切换一级路由地址/about显示About组件再在About组件中点击导航栏Message实现切换二级路由地址/about/message显示Message组件实现多级路由切换。三、四...级路由同理。
三、路由的query参数
1.传递参数
在Message.vue组件的<router-link></router-link>中通过path指定要跳转的路由及query指定要携带的query参数
Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 指定要跳转路由和携带的query参数 -->
<router-link
:to="{
path: '/about/message/detail', //为该路由时切换Detail组件
query: {
id: m.id,
title: m.title,
},
}"
>
{{ m.title }}
</router-link>
</li>
</ul>
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</template>
<script>
export default {
name: "Message",
data() {
return {
messageList: [
{ id: "001", title: "消息001" },
{ id: "002", title: "消息002" },
{ id: "003", title: "消息003" },
],
};
},
};
</script>
2.接收参数
在接收参数的路由组件Detail.vue组件中通过$route配置项中的query属性接收参数
Detail.vue
<template>
<div>
<p>消息id:{{ $route.query.id }}</p>
<p>消息title:{{ $route.query.title }}</p>
</div>
</template>
/* .. */
四、命名路由
可通过给路由命名从而实现简化跳转(在多级路由跳转时无需写完整路径)
const router = new VueRouter({
routes:[
{
path:'/about',
component:About,
children: [
{
path:'message',
component:Message,
children: [
{
name:'particulars', // 为第三级路由命名为'particulars'
path:'detail',
component:Detail,
}
]
},
]
},
]
})
配合上文的query参数传递可简写为:
<template>
<div>
<!-- 跳转路由并携带query参数,此时不需要写三级路由完整路径/about/message/detail -->
<router-link
:to="{
name: 'particulars',
query: {
id: m.id,
title: m.title,
},
}"
>
</router-link>
<router-view></router-view>
</div>
</template>
五、路由的params参数
1.传递参数
类似于路由的query参数传递规则,路由的params参数传递只需将<router-link></router-link>中的query对象改为params对象并指定要携带的参数
<router-link
:to="{
name: 'particulars',
params: {
id: m.id,
title: m.title,
},
}"
>
</router-link>
注意:若使用params传递参数必须使用命名路由,使用path无效;
2.接收参数
类似于路由的query参数传递规则,在接收参数的路由组件中通过$route配置项中的params属性接收参数
<template>
<div>
<p>消息id:{{ $route.params.id }}</p>
<p>消息title:{{ $route.params.title }}</p>
</div>
</template>
注意:接收params参数的路由组件需在该路由规则中使用占位符接收params参数
{
name:'particulars',
path:'detail/:id/:title/', //使用占位符声明接收params参数
component:Detail
}
六、路由的props配置
除了可以在需要接收参数的路由组件的的$route.query或$route.params传递参数供该路由组件获取参数外,还可以通过路由的props配置传递参数,具体规则如下:
在需要接收参数的路由组件中配置props
- 方式一:props对象式
- 方式二:props布尔值式
- 方式三:props函数式
方式一
{
name:'particulars',
path:'detail',
component:Detail,
// props对象式写法
props:{
school:"ZZULI",
name:"JV_32"
}
}
在接收参数的路由组件Detail中通过props接收参数
<template>
<div>
<h3>School:{{ school }}</h3>
<h3>Name:{{ name }}</h3>
</div>
</template>
<script>
export default {
name: "Detail",
props: ["school", "name"],
};
</script>
该方式一般不常用,因为传递的为死数据
方式二
{
name:'particulars',
path:'detail/:id/:title', // 从params中拿参数,需要占位符
component:Detail,
//props布尔值为真,就将该路由接收到的所有params参数以props的方式传给Detail组件
props:true
}
在接收参数的路由组件Detail中通过props接收参数
<template>
<div>
<p>{{ id }}</p>
<p>{{ title }}</p>
</div>
</template>
<script>
export default {
name: "Detail",
props: ["id", "title"],
};
</script>
方式三
{
name:'particulars',
path:'detail', // 从query中拿参数,不需要占位符
component:Detail,
// props函数式,参数为回调函数,返回的对象中的每一组key-value都通过props传给Detail组件
props($route) {
return {
id:$route.query.id,
title:$route.query.title
}
}
}
同上,在接收参数的路由组件Detail中通过props接收参数,不同的是,通过props函数式的写法获取参数不仅仅局限于获取params中的数据,也可以从query中拿数据。
优点:通过props实现路由参数传递,无需在接收参数的组件模板中通过写一连串的$route.params或$route.query获取参数
七、缓存路由组件
通过点击导航栏切换路由实现组件间的切换实则是切换路由的销毁和被切换路由的挂载,也就是切换前的路由走的是销毁流程,切换后的路由重新挂载到页面中,那么我们若需要保留在原先的路由组件中的操作不被销毁,那么就引入了缓存路由组件
方式:通过在指定路由呈现位置的<router-view></router-view>标签外使用<keep-alive></keep-alive>包裹并通过设置include指定要缓存的组件,如下:缓存News组件
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
未缓存News组件:
缓存了News组件:
若要缓存多个路由组件,那么include应设置为数组的形式
<keep-alive :include="["News","Message"]">
<router-view></router-view>
</keep-alive>
八、两个路由的生命周期钩子
场景:当为路由组件News设置缓存后,切换别的路由组件后该组件不会被销毁,若该路由组件中设置了定时器,切换后定时器将不停地执行,极大地影响了性能,因此,路由组件啊拥有自己的两个生命周期钩子。
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
1.activated
activated(),路由组件被激活时触发。在以上场景中,可以在该钩子函数中开启定时器
2.deactivated
deactivated(),路由组件失活时触发。同理,在以上场景中,可在该钩子函数中关闭定时器,当切换其他路由组件后该组件失活,随即关闭定时器,不消耗性能。
<template>
/* 省略。。 */
</template>
<script>
export default {
name: "News",
activated() { // News组件激活时触发,开启定时器
console.log("News组件被激活了!");
this.timer = setInterval(() => {
console.log("@");
}, 16);
},
deactivated() { // News组件失活后触发,关闭定时器
console.log("News失活了!");
clearInterval(this.timer);
},
};
</script>
不断切换控制News组件显示与不显示,控制台输出如下:
九、路由守卫
在Vue项目中,我们一般会设置一个路由守卫,为防止用户未登录直接从地址栏输入地址访问网站其他页面。
1.全局守卫
不管跳转哪个地址,都会触发全局路由守卫
beforeEach()
全局前置路由守卫,当路由初始化及路由切换前调用。函数接收三个参数,to,from,next,分别标识到哪个地址去,从哪个地址来,以及放行。该函数一般用以用户登录的校验
场景:部分模块(路由组件)只有特定用户可以访问到,需要校验访问者是否符合条件
实现:为需要切换的路由组件规则中添加meta配置项并添加该路由切换是否需要校验的属性isAuth:true;当点击切换到该路由前执行全局前置路由守卫beforeEach(),如下:
{
path:'home',
component:Home,
meta: {
isAuth:true, // 切换至该路由时是否需要校验用户信息
},
}
// 全局前置路由守卫————初始化及每次路由切换之前被调用
router.beforeEach((to,from,next) => {
// to:跳转到xxx
// from:从xxx跳转来
// next():放行,执行下一步
if(to.meta.isAuth) { // 判断跳转到该路由是否需要信息校验
if(localStorage.getItem('school') === 'ZZULI'){ // 假定从浏览器缓存读取信息并校验
next(); // 验证通过,执行next(),放行
}else{
alert('校验不通过,无权限访问!');
}
}else{
next(); // 该路由切换不需要验证,直接执行next(),放行
}
})
afterEach()
如上述,当校验通过后成功切换该路由后执行全局后置路由守卫,该函数接收两个参数,to,from
场景:切换路由后设置该路由组件的标题为“主页”
实现:在该路由组件规则中的meta配置项追加该路由组件的标题属性:title: "主页",当切换到该路由后执行全局后置路由守卫afterEach(),如下:
{
path:'home',
component:Home,
meta: {
isAuth:true, // 切换至该路由时是否需要校验用户信息
title:'主页' // 切换至该路由时显示的组件标题
},
}
// 全局后置路由守卫————初始化时执行及每次路由切换后执行
router.afterEach((to,from) => {
document.title = to.meta.title;
})
2.独享守卫
beforeEnter()
对比于全局路由守卫服务全部路由的特点:当任意切换路由组件时调用全局前、后置路由守卫函数。
独享路由守卫特点为:只服务于专门设置此守卫的路由,用法与全局守卫一致
该守卫直接配置在需要此守卫的路由的路由规则中,如下:
{
path:'/home',
component:Home,
meta:{isAuth:true,title:'主页'},
beforeEnter(to,from,next){
if(to.meta.isAuth){
if(localStorage.getItem('school') === 'ZZULI'){
next()
}else{
alert('暂无权限查看')
}
}else{
next()
}
}
}
3.组件内守卫
也可以在路由组件内直接定义路由守卫,称为组件内守卫
beforeRouteEnter()
进入守卫:通过路由规则,进入该组件时被调用
注意:要区别于全局前置路由守卫,该守卫是在进入该组件后调用
具体顺序为:beforeEach() → beforeRouteEnter() → afterEach()
<script>
export default {
name: "Home",
beforeRouteEnter(to, from, next) {
console.log("你已通过路由规则进入Home组件");
next(); //放行
},
};
</script>
beforeRouteLeave()
离开守卫:通过路由规则,离开该组件时被调用,这个守卫通常用来禁止用户还未保存修改前离开,可通过next(false)来取消
beforeRouteLeave: (to, from, next) => {
if (confirm("你确定要离开吗") == true) {
next();
} else {
next(false);
}
},