vue-router
安装与配置
vue2 得用vue-router3
npm i vue-router@3
vue3 得用vue-router4
建立一个文件夹router
index.js
import About from "@/components/About.vue";
import Home from "@/components/Home.vue";const router = new VueRouter({routes: [{path:'/home',component: Home}]
})export default router;
main.js
import Vue from 'vue'
import App from './App.vue'
import VueRouter from 'vue-router'
import router from '@/router'Vue.use(VueRouter)Vue.config.productionTip = false
new Vue({render: h => h(App),router
}).$mount('#app')
路由基本使用
App.vue
<template><div class="app"><div class="row"><div class="col-xs-offset-2 col-xs-8"><div class="page-header"><h2>Vue Router Demo</h2></div></div></div><div class="row"><div class="col-xs-2 col-xs-offset-2"><div class="list-group"><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></div><div class="col-xs-6"><div class="panel"><div class="panel-body"><router-view></router-view></div></div></div></div></div>
</template>
<script>
export default {name: 'App'
}
</script>
router-link 本质上就是a标签,我们要使用to属性到我们的路径
router-view是我们要展示的位置
index.js
import About from "@/components/About.vue";
import Home from "@/components/Home.vue";
import VueRouter from "vue-router";const router = new VueRouter({routes: [{path:'/home',component: Home},{path: '/about',component: About}]
})export default router;
两个组件,就是两行字
几个注意点
路由的页面一般放到pages文件夹
通过切换隐藏的路由组件,实际上是被销毁的
每个路由组件都有自己的$route
属性,里边存储着自己的路由信息
整个应用这有一个router,可以通过组件的$router
获取到
嵌套路由
import About from "@/components/About.vue";
import Home from "@/components/Home.vue";
import Message from "@/components/Message.vue";
import News from "@/components/News.vue";
import VueRouter from "vue-router";const router = new VueRouter({routes: [{path:'/home',component: Home,children: [{path: 'news',component: News},{path: 'message',component: Message},]},{path: '/about',component: About,children: [{path: 'news',component: News},{path: 'message',component: Message},]}]
})export default router;
注意嵌套路由不要再加/
,因为vue会自动补一个/
,如果手欠多写了一个,会找不到
<router-link to="/home/news">News</router-link>
且router-link必须这么写
query参数
路由组件之间的传值使用query参数
传递参数
<li v-for="msg in messageList" :key="msg.id">
<router-link :to="`/home/message/detail?id=${msg.id}&title=${msg.title}`">
{{msg.title}}
</router-link>
</li>
传递变量不可以直接写:
了事,:会把里边的值看成是js代码,还是使用模版字符串``,在里边使用${},这样的写法和php的模版字符串是一样的
对象写法
<li v-for="msg in messageList" :key="msg.id"><router-link :to="{path:'/home/message/detail',query: {id:msg.id,title: msg.title}}">{{msg.title}}</router-link>
</li>
对象写法更为清晰,推荐
接收参数
<div>消息编号:{{$route.query.id}}</div><div>消息标题:{{$route.query.title}}</div>
命名路由
有时候路由路径太长,可以起一个路由的名字
const router = new VueRouter({routes: [{path:'/home',component: Home,children: [{path: 'news',component: News},{path: 'message',component: Message,children: [{name:'xiangqing',path: 'detail',component: Detail,}]},]}]
})
这里我给detail,起了个名字,xiangqing
使用的时候,我们就不能用path,得用name
<router-link :to="{name:'xiangqing',query: {id:msg.id,title: msg.title}
}">{{msg.title}}</router-link>
params参数
必须在路由配置中配置,占位符
const router = new VueRouter({routes: [{path:'/home',component: Home,children: [{path: 'news',component: News},{path: 'message',component: Message,children: [{name:'xiangqing',path: 'detail/:id/:title',component: Detail,}]},]}]
})
<li v-for="msg in messageList" :key="msg.id"><router-link :to="{name:'xiangqing',params: {id:msg.id,title: msg.title}}">{{msg.title}}</router-link> </li>
配置params
注意,这里不能用path,必须用name
接收参数
<div>消息编号:{{$route.params.id}}</div>
<div>消息标题:{{$route.params.title}}</div>
props配置
props配置,是为了简写拿到的qurery和params
一共三种写法
值为对象
{name:'xiangqing',path: 'detail/:id/:title',component: Detail,props:{a:1,b:2}
}//接收
props:['a','b']
这种写法只能传送死数据
值为布尔值
{name:'xiangqing',path: 'detail/:id/:title',component: Detail,props:true
}
如果值为true,就会把路由组件收到的所有params参数,以propos传给Detail组件
缺点只能传params参数
值为函数
{name:'xiangqing',path: 'detail/:id/:title',component: Detail,props($route) {return {id: $route.params.id,title: $route.params.title}}
}//接受
props:['id','title']
我们可以直接写query或者params
这个写法比较通用
replace
浏览器的历史记录有两种写入方式:push和replace,其中push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push方式
开启replace模式:<router-link replace ...>News</router-link>
push方式的形式类似于路径压栈
特别注意replace是替换当前记录.举个例子
一共三个路径
localhost:8080#/
localhost:8080#/home
localhost:8080#/home/news
正常来说,按照压入栈的形式是如下的
localhost:8080#/home/news
localhost:8080#/home
localhost:8080#/
栈顶就是我们最后的news
如果我们在news开启replace模式,当我们点击news这个router-link
的时候,当前路由路径是localhost:8080#/home
,那么localhost:8080#/home/news
就会替换当前home的路径变成如下的
localhost:8080#/home/news
localhost:8080#/
我想说的是,他不会所有的都替换,只会替换当前的路径
编程式路由导航
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
this.$router.push({name:'xiangqing',params: {id:msg.id,title: msg.title}
})
push和replace是一样的,都写入一个配置对象就ok
go()传入数字,例如,go(2),往前走两步,go(-2)往回走2步
缓存路由组件
我们知道,路由组件在切换的时候,是会销毁路由组件,有的时候,我们不想销毁
那我们就找到哪里展示这些路由组件,写如下代码
//缓存一个<keep-alive include="News"><router-view></router-view></keep-alive>
//缓存多个<keep-alive :include="['News','Message']"><router-view></router-view></keep-alive>
注意,include这里的写的是组件名,组件名!!!
并且,如果不写的话,那就是这下面所有的组件都缓存
两个生命周期钩子
接上文,缓存路由组件,我们像一个场景,我们缓存了路由组件,路由组件不会去销毁,但是有时候,我们在这个路由组件里边写了定时器什么的,如果我们不关掉,定时器在其他地方就会一直运行,所以我们就可以引出这两个路由组件独有的生命周期钩子
我们可以在deactivated钩子里边关闭定时器
全局路由守卫
import About from "@/components/About.vue";
import Detail from "@/components/Detail.vue";
import Home from "@/components/Home.vue";
import Message from "@/components/Message.vue";
import News from "@/components/News.vue";
import VueRouter from "vue-router";const router = new VueRouter({routes: [{path:'/home',component: Home,meta: {title:'主页'},children: [{path: 'news',component: News,meta: {isAuth: true,title:'新闻'}},{path: 'message',component: Message,meta: {isAuth: true,title:'消息'},children: [{name:'xiangqing',path: 'detail/:id/:title',component: Detail,props($route) {return {id: $route.params.id,title: $route.params.title}}}]},]},{path: '/about',component: About,meta: {title:'关于'},children: [{path: 'news',component: News,meta: {isAuth: true,title:'新闻'}},{path: 'message',component: Message,meta: {isAuth: true,title:'消息'},},]}]
})router.beforeEach((to,from,next) => {if(to.meta.isAuth) {if(localStorage.getItem('name') === 'jjking') {next();} else {alert("没有权限查看");}} else {next();}
})router.afterEach((to,from,next) => {if(to.meta.title) {document.title = to.meta.title;} else {document.title = '我的系统';}
})
export default router;
全局路由守卫有点类似于,后端的过滤器interceptors,我初步认为,这个路由守卫是搭配后端的权限配置的
比如说,你是vip,就能看vip的内容,如果你不是vip就不能看
例如我上面这个例子,我们是在本地存储上写了一个,如下
router.beforeEach()这个函数的回调是,路由切换之前的回调函数
在这个时候我们进行权限的校验,如何标识什么接口需要权限的标识呢,我们就在router给我们准备的meta元信息里边写一个isAuth
如果为true,说明需要校验,写入我们希望的校验规则,这里我是写死的,一般项目中,我认为是从后端去获取校验的规则,比如某某用户拥有什么权限,有什么权限就给看什么
next()就是给放行
独享路由守卫
和全局路由守卫差不多,不过这个会配置在路由组件里边的,且名字不同
{path: 'news',component: News,meta: {isAuth: true,title:'新闻'},beforeEnter(to,from,next) {if(to.meta.isAuth) {if(localStorage.getItem('name') === 'jjking') {next();} else {alert("没有权限查看");}} else {next();}}}
名字叫做beforeEnter,且没有独享后置路由守卫
组件内路由守卫
路由守卫总结
全部的路由守卫的顺序是如下的
前置 => 独享 => 进入 => 离开 => 后置
比较容易混淆的是,组件和前后置路由守卫,组件内路由守卫是组件内部的自己的独特的业务逻辑,是独有的,且也会影响是否放行
路由器的两种工作模式
对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器
hash模式:
地址中永远带着#号,不美观
若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
兼容性较好
history模式:
地址干净,美观
兼容性和hash模式相比略差
应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题