路由
路由是键值对,key 对应不同 url 路径,value 对应相应组件。以实现 SPA 不同页面的切换。
vue-router 是什么
vue 的一个插件库,专门用来实现 SPA 应用。
SPA 是什么
单页 Web 应用(single page web application)。 整个应用只有一个完整的页面,点击页面中的导航链接不会刷新页面,只会做页面的局部更新。数据通过 ajax 请求获取。
路由的使用
router.js
//创建并暴露一个路由器
export default new VueRouter({
routes: [
{
path: "/about",
component: About,
},
{
path: "/home",
component: Home,
},
],
});
main.js
Vue.use(VueRouter);
//创建vm
new Vue({
el: "#app",
render: (h) => h(App),
router: router,
});
App.vue
<!-- Vue中借助router-link标签实现路由的切换 -->
<router-link to="/about">About</router-link>
<router-link to="/home">Home</router-link>
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
路由的注意点
- 路由切换意味着前端组件的切换,处于非活跃的组件是被销毁等待之后重建。
- 每个组件拥有自己的$route 属性,保存自己的路由信息
- 整个应用只有一个$router 属性
router-link 的本质
router-link
最后会转成<a>
标签
路由的历史记录采用栈结构存储,默认采用 push 模式;给<router-link>
设置 replace 属性表示路由记录采用替换模式。
多级路由
router.js
//创建并暴露一个路由器
export default new VueRouter({
routes: [
{
path: "/about",
component: About,
},
{
path: "/home",
component: Home,
// 子路由不用加 /
children: [
{
path: "news",
component: News,
},
{
path: "message",
component: Message,
},
],
},
],
});
Home.vue
<router-link to="/home/news">News</router-link>
<router-link to="/home/message">Message</router-link>
<router-view></router-view>
命名路由
使用 name 属性简化路由路径 🌻
router.js
{
path: "message",
component: Message,
children: [
{
name: "routeName",
path: "detail",
component: Detail,
},
],
},
Message.vue
<router-link :to="{ name: 'routeName' }"></router-link>
路由传参
$route.query
通过 $route.query 对象传递参数。
router.js
export default new VueRouter({
routes: [
{
path: "/home",
component: Home,
children: [
{
path: "news",
component: News,
},
{
path: "message",
component: Message,
children: [
{
path: "detail",
component: Detail,
},
],
},
],
},
],
});
Detail.vue
<template>
<ul>
<li>消息编号:{{ $route.query.id }}</li>
<li>消息标题:{{ $route.query.title }}</li>
</ul>
</template>
Home.vue
<template>
<div>
<h2>Home组件内容</h2>
<div>
<ul>
<li>
<router-link to="/home/news">News</router-link>
</li>
<li>
<router-link to="/home/message">Message</router-link>
</li>
</ul>
<router-view></router-view>
</div>
</div>
</template>
Message.vue
<template>
<div>
<ul>
<li v-for="m in messageList" :key="m.id">
<!-- 跳转路由并携带query参数,to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>; -->
<!-- 跳转路由并携带query参数,to的对象写法 -->
<router-link
:to="{
path: '/home/message/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>
$route.params
通过 $route.params 对象传递参数。
配置路由 path 属性的时候需要使用占位符声明接收参数
path:'detail/:id/:title',
特别注意
此时 router-link 使用 to 的对象写法,不能使用 path 配置项,必须使用 name 属性配置
props
路由配置可以接收 props 选项,目的就是为了让路由组件更方便的收到参数。
router.js
{
path:'detail',
component:Detail,
// props:{a:1,b:'hello'}
// props:true
props($route){
return {
id:$route.query.id,
title:$route.query.title,
}
}
}
- props 的第一种写法,值为对象,该对象中的所有 key-value 都会以 props 的形式传给 Detail 组件
- props 的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有 params 参数,以 props 的形式传给 Detail 组件。局限在于不能接收 query 参数
- props 的第三种写法,值为函数,vue-router 会传入$route 参数,可以使用解构赋值的形式精简代码
函数式路由
不借助 <router-link>
实现路由跳转,让路由跳转更加灵活。
利用 VueRouter 对象实例的方法,Vue 项目里一般通过 this.$router 访问。
this.$router.push(options: object)
this.$router.replace(options: object)
this.$router.back()
this.$router.forward()
this.$router.go(n: number)
缓存路由组件
- 缓存单个路由
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
- 缓存多个路由组件
<keep-alive :include="['News', 'Message']">
<router-view></router-view>
</keep-alive>
- 缓存所有路由组件
<keep-alive>
<router-view></router-view>
</keep-alive>
生命周期钩子
- activated,VueRouter 对象独有,组件激活时调用
- deactivated,VueRouter 对象独有,组件失活时调用
路由守卫
路由守卫既对路由进行权限控制。
全局守卫
在路由配置文件里设置 meta 元属性即可 ✍️
- router.js
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'}
},
]
}
- 全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to, from, next) => {
if (to.meta.isAuth) {
//判断是否需要鉴权
if (localStorage.getItem("school") === "xxx") {
next();
} else {
alert("学校名不对,无权限查看!");
}
} else {
next();
}
});
- 全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to, from) => {
document.title = to.meta.title || "zhang13press";
});
独享守卫
很多时候,需要给某个特殊组件设置路由权限,可在 router.js 路由配置文件内给该组件单独配置 beforeEnter 属性
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'},
beforeEnter: (to, from, next) => {
if (to.meta.isAuth) {
//判断是否需要鉴权
if (localStorage.getItem("school") === "xxx") {
next();
} else {
alert("学校名不对,无权限查看!");
}
} else {
next();
}
};
}
组件内守卫
在对应组件内设置路由规则,而不是在路由配置文件。
xxx.vue
export default {
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to, from, next) {
if (to.meta.isAuth) {
//判断是否需要鉴权
if (localStorage.getItem("school") === "xxx") {
next();
} else {
alert("学校名不对,无权限查看!");
}
} else {
next();
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave(to, from, next) {
next();
},
};
路由模式
- hash,默认模式,url 中
#
后的内容就是 hash 值,它不会包含在 HTTP 请求中,既不会带给服务器 - history,在路由配置文件添加
mode:'history'
开启,node.js 一般采用connect-history-api-fallback
中间件解决携带前端路径造成的 404 问题
小结
- beforeEach
- afterEach
- beforeEnter
- beforeRouteEnter
- beforeRouteLeave