vue-router是Vue的一个插件库,专门用来做SPA应用(single page web application)。
SPA(single page web application)应用就是单页Web应用,不会刷新页面,只做页面的局部更新。数据需要通过ajax请求获取。
路由
一个路由就是一组映射关系(key-value),key是路径,value是function或component。
路由分为前端路由和后端路由后端路由中的value是function。前端路由的value是component,用于页面内容,当浏览器的路径改变时,对应的组件就会显示。
比如下图就是前端路由根据不同路径展示不同的组件。
路由的基本使用
安装vue-router插件
npm i vue-router
使用插件
Vue.use(VueRouter)
新建一个router/index.js文件编写router配置项
// 该文件专门创建整个应用的路由器
import VueRouter from "vue-router";
// 引入路由组件
import AboutPage from '../pages/AboutPage.vue';
import HomePage from '../pages/HomePage.vue';
// 创建并暴露一个路由器
export default new VueRouter({
routes: [
// 设置路由规则
{
path: '/about',
component: AboutPage
},
{
path: '/home',
component: HomePage
},
]
})
在组件中使用router-link标签实现切换(active-class可配置高亮样式),本质上就是a标签。
to属性 用于设置路径。
<router-link class="bla bltop" active-class="active" to="/about">About</router-link>
replace属性 用于设置页面跳转时操作浏览器记录的模式,push模式(默认)是追加历史记录,replace模式是替换当前记录。
<router-link replace to="/about" class="nav-top" active-class="active">
<span>
About
</span>
</router-link>
在组件中使用router-view标签指定展示的位置
<router-view></router-view>
几个注意点:
- 路由组件通常存放在
pages文件夹中,一般组件通常存放在components文件夹中。 - 通过切换,“隐藏”了的路由组件默认是被销毁的,需要的时候再去挂载。
- 每个组件都有自己的
route属性,其中存储着自己的路由信息,通过$route属性获取。 - 整个应用只有一个
router路由器,可以通过组的$router属性获得。
嵌套路由
嵌套路由在配置时需要在对应的父级路由规则中添加children配置项
routes: [
{
name: 'guanyu',
path: '/about',
components: {
default: () => import('../pages/myAbout.vue'),
}
},
{
path: '/home',
components: {
default: () => import('../pages/myHome.vue'),
myHomeList: () => import('../pages/myHomeList.vue')
},
children: [
{
path: 'news',
components: {
default: () => import('../pages/myNews.vue')
}
},
{
path: 'message',
components: {
default: () => import('../pages/myMessage.vue')
},
children: [
{ path: 'detail',
component:() => import('../pages/myDetail.vue')
}
]
}
]
},
],
组件中实现路由跳转时注意路径要写完整
<router-link to="/home/message" active-class="active">
<span>Message</span>
</router-link>
命名路由
路由传参
第一种方式是组件可以通过query在页面跳转时传递参数,在to属性中使用问号?携带参数。
- 传递展示列表的id和title属性。
<template>
<div>
<ul class="list">
<li class="item" v-for="m in messageList" :key="m.id">
<!-- to的字符串写法 -->
<!-- <router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{ m.title }}</router-link> -->
<!-- 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: 'myMessage',
data(){
return {
messageList: [
{id: '001', title: '消息001'},
{id: '002', title: '消息002'},
{id: '003', title: '消息003'},
]
}
}
}
</script>
- 组件通过
query接收传递的id和title。
<ul>
<li>消息编号:{{$route.query.id}}</li>
<li>消息标题:{{$route.query.title}}</li>
</ul>
第二种方式是组件还可以通过params在页面跳转时传递参数,在to属性中使用斜线/携带参数。
- 配置路由时要声明接收
params参数。
{
path: 'message',
components: {
default: () => import('../pages/myMessage.vue')
},
children: [
{ path: 'detail/:id/:title', // 使用占位符声明接收params参数
component:() => import('../pages/myDetail.vue')
}
]
}
- 组件传递参数时和query类似的,但要注意如果使用to的对象写法,则必须使用
name配置,不能使用path。
<template>
<div>
<ul class="list">
<li class="item" v-for="m in messageList" :key="m.id">
<!-- to的字符串写法 -->
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{ m.title }}</router-link>
<!-- to的对象写法 -->
<!-- <router-link :to="{
name: 'detail'
query: {
id: m.id,
title: m.title
}
}">{{ m.title }}</router-link> -->
</li>
</ul>
<router-view></router-view>
</div>
</template>
- 组件接收参数
<template>
<ul>
<li>消息编号:{{$route.params.id}}</li>
<li>消息标题:{{$route.params.title}}</li>
</ul>
</template>
除此之外,配置路由时可以通过props配置项让路由组件更方便收到参数,组件可以通过props配置项接收到参数,再应用到模板中。
children: [
{ path: 'detail/:id/:title',
component:() => import('../pages/myDetail.vue'),
// props的第一种写法,该对象中的所有键值对都会通过props传给detail组件
// props: {
// a: 1,
// b: 'hello'
// }
// 第二种写法,布尔值,布尔值为true,则把路由收到的params参数通过props传给detail组件
// props: true,
// 第三种写法:props为函数,该函数返回的对象中每一组键值对都会通过props传给detail组件,参数是$route
props($route){
return {
id: $route.params.id,
title: $route.params.title
}
}
}
]
编程式路由导航
不借助router-link标签实现路由跳转,让路由跳转更加灵活。
为此我们可以用router中两个个API实现任意标签路由跳转,并且可以设置他们的浏览器记录模式。
methods: {
pushShow(m){
// push模式
this.$router.push({
name: 'xiangqing',
params: {
id: m.id,
title: m.title
}
})
},
repalceShow(m){
// repalce模式
this.$router.repalce({
name: 'xiangqing',
params: {
id: m.id,
title: m.title
}
})
}
}
除了以上两种还有其它几种API
this.$router.forwrad() // 前进
this.$router.back() // 后退
this.$router.go() // 可前进可后退
缓存路由组件
为了让不展示的路由组件保持挂载不被销毁
<keep-alive include="News">
<router-view>
</router-view>
</keep-alive>
两个新的生命周期钩子
路由组件独有的两个钩子,用于捕获路由组件的激活状态。
activated() 路由组件被激活时触发。
deactivated() 路由组件失活时触发。
<script>
export default {
name: 'myNews',
data(){
return {
messageList: [
{id: '001', title: '新闻001'},
{id: '002', title: '新闻002'},
{id: '003', title: '新闻003'},
]
}
},
activated(){
console.log('News组件激活了');
},
deactivated(){
console.log('News组件停用了');
}
}
</script>
路由守卫
路由守卫是为了对路由进行权限控制,分为全局守卫、独享守卫,组件内守卫。
全局路由守卫
全局路由守卫又分为前置守卫和后置守卫。
全局前置路由守卫 初始化的时候被调用,每次路由切换之前也会被调用。
全局后置路由守卫 初始化的时候被调用,每次路由切换之后也会被调用。
meta属性 是路由配置项的一个对象属性,用户可以在其中自定义需要的属性。
// 全局前置路由守卫 初始化的时候被调用,每次路由切换之前也会被调用
router.beforeEach((to, from, next)=>{
console.log('前置路由守卫', to, from);
if(to.meta.isAuth){ // 判断是否需要鉴权
if(localStorage.getItem('user') === 'kng'){
next();
}else{
alert('用户权限不够');
}
}else{
next();
}
})
// 全局后置路由守卫 初始化的时候被调用,每次路由切换之后也会被调用
router.afterEach((to,from, next)=>{
console.log('后置路由守卫', to, from, next);
if(to.meta.title){
document.title = to.meta.title; // 修改网页的title
}else{
document.title = 'vue_test';
}
})
独享路由守卫
某一个路由独享的路由守卫,
beforeEnter: (to, from, next) => {
console.log('独享路由守卫', to, from);
if(to.meta.isAuth){ // 判断是否需要鉴权
if(localStorage.getItem('user') === 'kng'){
next();
}else{
alert('用户权限不够');
}
}else{
next();
}
}
组件内路由守卫
通过路由规则,进入或离开组件时被调用。
// 通过路由规则进入该组件时被调用
beforeRouteEnter (to, from, next) {
console.log('App---beforeRouteEnter', to, from);
if(to.meta.isAuth){ // 判断是否需要鉴权
if(localStorage.getItem('user') === 'king'){
next();
}else{
alert('用户权限不够');
}
}else{
next();
}
},
// 通过路由规则离开该组件时被调用
beforeRouteLeave (to, from, next) {
console.log('App---beforeRouteLeave', to, from, next);
next();
}
路由器的工作模式
路由器的工作模式有两种,history模式和hash模式。
对于一个url来说,hash值就是#号及其后面的内容,不会包含在HTTP请求中,即不会带给服务器。它虽然不美观但是兼容性比较好。
history模式的url地址干净美观,兼容性略差,部署上线时需要后端人员支持解决刷新页面服务端404的问题。