路由:简单来说类似于路由器,中转站。
1.理解: 一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理。
2.前端路由:key是路径,value是组件。
一 基本使用
1.安装vue-router
npm i vue-router
2.应用插件
main.js中
Vue.use(VueRouter)
3.编写router配置项和第一二级
创建router包然后在里面创建index.js
多级路由:
import VueRouter from "vue-router";
import CountVuex from '../components/vuex/CountVuex.vue'
import PersionListVuex from '../components/vuex/PersionListVuex.vue'
import List from '../components/List.vue'
import HomeTop from '../components/HomeTop.vue'
//创建并暴露一个路由器
export default new VueRouter({
mode:"history",
linkActiveClass:'is-active',
//path 和 name 用一个就行,但是可以在index里面都写上
routes:[{
path:'/HomeTop', //指定要跳转的路径
name:'jiaogao',//组件路由可以通过路径但是如果比如第3级路由时路径写的比较长,所以可以用名字就行
component:HomeTop, //指定要跳转的组件
children: [{
name:'jihe',
path:'List', //指定要跳转的路径
component:List, //指定要跳转的组件
children:[
{
path:'CountVuex', //指定要跳转的路径
name:'shuliang',//组件路由可以通过路径但是如果3级路由时路径写的比较长,所以可以用名字就行
component:CountVuex 指定要跳转的组件
},
{
path:'PersionListVuex',//path:'PersionListVuex/:id/:title',
name:'renjihe',//组件路由可以通过路径但是如果3级路由时路径写的比较长,所以可以用名字就行
component:PersionListVuex,
//props 写法如下:
//route的props=>第一种写法:值为对象,该对象中所有的key-value都会以props的形式传给PersionListVuex组件
//props:{a:1,b:'hello'}
//route的props=>第二种写法:值为布尔值true时,会把该路由组件收到的所有params(router-link中得用params而不是query,index.js中path:'PersionListVuex/:id/:title)参数以props形式传给PersionListVuex组件,组件里面props:['id','title'] 这样写,到时候直接在PersionListVuex中 {{id}} {{title}}就行
//props:true
//route的props=>第三种写法,为回调函数。组件里面props:['id','title'] 这样写
// props($route){
// return {id:$route.query.id,title:$route.query.title}
// }
//route的props=>第三种写法简写(结构赋值的连续写法),为回调函数。组件里面props:['id','title'] 这样写
// props({query:{id,title}}){
// return {id,title}
// }
}
]
}]
}
]
})
第一级 HomeTop.vue
<!--
1:路由组件通常放在pages文件夹,一般组件通常存放在componentswe文件夹
2:通过切换,‘隐藏’了的路由组件,默认是被销毁,需要的时候在去挂载
3:每个组件都有自己的$route属性。里面存着自己的路由信息
4:整个应用只有一个router($router相比于$route 多一个r) 可以通过组件的$router属性获取到。
5:router-link:
to:表示目标路由的链接,该值可以是一个字符串,也可以是动态绑定的描述目标位置的对象
event:代表触发的事件。event="mouseover" 代表鼠标移入就触发不需要点。
tag:使用tag类指定何种标签,同样它还是会监听点击,触发导航。比如:tag="li"
https://zhuanlan.zhihu.com/p/150773649
6: router-link 的push(默认)和replace 区别:
1、this.$router.push()
跳转到指定的url,此方法会向history栈添加一个记录,点击后退会返回到上一个页面。
2、this.$router.replace()
跳转到指定的url,此方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
-->
<template>
<div>
<div>
<!--注意:单纯如下传字符串没问题,如下写就行,如果是带有动态值则应该像List.vue那样写 to前加冒号 然后 `` ${{}}-->
<!-- <router-link to="/HomeTop/List?id=1&title=你好啊,小悦悦">导航一</router-link> -->
<router-link :to="{
name:'jihe',
//query 则上面一行可以是name也可以是path,但是如果换成params则上面这一行只能是name 并且index.js路由中只能 path:'HomeTop/:id/:title' 这样写
//template中获取参数则:$route.params.id $route.params.title
query:{
id:1,
title:'你好啊,小悦悦'
}
}">导航一</router-link>
<!--导航一下面下一级组件内容会在这里展示-->
<router-view></router-view>
</div>
</div>
</template>
<script>
export default{
// eslint-disable-next-line vue/multi-word-component-names
name:'HomeTop',
}
</script>
第二级 List.vue
<!--
1:路由组件通常放在pages文件夹,一般组件通常存放在componentswe文件夹
2:通过切换,‘隐藏’了的路由组件,默认是被销毁,需要的时候在去挂载
3:每个组件都有自己的$route属性。里面存着自己的路由信息
4:整个应用只有一个router($router相比于$route 多一个r) 可以通过组件的$router属性获取到。
5:router-link:
to:表示目标路由的链接,该值可以是一个字符串,也可以是动态绑定的描述目标位置的对象
event:代表触发的事件。event="mouseover" 代表鼠标移入就触发不需要点。
tag:使用tag类指定何种标签,同样它还是会监听点击,触发导航。比如:tag="li"
https://zhuanlan.zhihu.com/p/150773649
6: router-link 的push(默认)和replace 区别:
1、this.$router.push()
跳转到指定的url,此方法会向history栈添加一个记录,点击后退会返回到上一个页面。
2、this.$router.replace()
跳转到指定的url,此方法不会向history里面添加新的记录,点击返回,会跳转到上上一个页面。上一个记录是不存在的。
-->
<template>
<div>
<ul>
<li>
<!--query传参 一般写法 start-->
<!--event="mouseover" 代表鼠标移入就触发不需要点 -->
<!--注意:单纯如下传字符串没问题,如下写就行,如果是带有动态值则应该像List.vue那样写 to前加冒号 然后 `` ${{}}-->
<!-- <router-link :to="`/HomeTop/List/CountVuex?titleA=${id}`">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link> -->
<!--query传参 一般写法 end-->
<!--query传参 对象写法 start-->
<router-link replace :to="{
//path:'/HomeTop/List/CountVuex',
name:'shuliang',//组件路由可以通过路径但是如果3级路由时路径写的比较长,所以可以用名字就行
query:{
titleA:id
}
}">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link>
<!--query传参 对象写法 end-->
</li>
<li>
<!--注意:单纯如下传字符串没问题,如下写就行,如果是带有动态值则应该像List.vue那样写 to前加冒号 然后 `` ${{}}-->
<router-link :to="`/HomeTop/List/PersionListVuex?titleB=${title}`">
<button>PersionListVuex--{{id}}--{{title}}</button>
</router-link>
<!-- <div>
<router-view name="PersionListVuex"></router-view>
</div> -->
</li>
</ul>
<router-view></router-view>
</div>
</template>
<script>
export default{
name:'List',
data(){
return{
id:'',
title:''
}
},
mounted(){
this.id = this.$route.query.id
this.title = this.$route.query.title
}
}
</script>
二 如上的解释和说明
1.路由的跳转问题(router->index.js 中path和name属性都写上方便一下两种方式)
通过path跳转:
<router-link to="/HomeTop/List/CountVuex">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link>
如上to中路径必须是router index.js 中 path 拼接完整路径。
通过name跳转(组件路由可以通过路径但是如果3级路由时路径写的比较长,所以可以用名字就行):
<router-link replace to="{
//path:'/HomeTop/List/CountVuex',
name:'shuliang'
}">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link>
2.传参接收参数问题
to路径后面 ?拼接传参数:
<router-link :to="`/HomeTop/List/CountVuex?titleA=${id}`">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link>
注意:
- 如上是动态传参 to 前面加 :切记
- 动态传参 " " 之间要加 `` 切记
如果不是动态 ?传参数 则如下写就行:
to="/HomeTop/List?id=1&title=你好啊,小悦悦"
具体值通过如下分别获取:
this.id = this.$route.query.id
this.title = this.$route.query.title
router-link 中 query对象传参
<router-link :to="{
name:'jihe',
//query 则上面一行可以是name也可以是path,但是如果换成params则上面这一行只能是name 并且index.js路由中只能 path:'HomeTop/:id/:title' 这样写
//template中获取参数则:$route.params.id $route.params.title
query:{
id:1,
title:'你好啊,小悦悦1111'
}
}">导航一</router-link>
注意:
- query对象形式传参数时 to 里面 可以用name也可以用path
- to前 : to后 " "
具体值通过如下分别获取:
this.id = this.$route.query.id
this.title = this.$route.query.title
router-link 中 param对象传参
第一级:
<router-link :to="{
name:'jihe',
params:{
id:1,
title:'你好啊,小悦悦1111params'
}
}">导航一</router-link>
注意:
- params则上面这一行只能是name 切记切记
- to前 : to后 " "
第一级对应 index.js
export default new VueRouter({
mode:"history",
routes:[{
path:'/HomeTop/:id/:title', //指定要跳转的路径
name:'jiaogao',
component:HomeTop, //
.......
index.js 中params写法这样写:
path:'/HomeTop/:id/:title',
具体值通过如下分别获取:
this.id = this.$route.params.id
this.title = this.$route.params.title
路由的props接收参数
作用:让路由组件更方便的收到参数
route index.js
{
name:'xiangqing',
path:'detail/:id',
component:Detail,
//第一种写法:props值为对象,该对象中所有的key-value的组合最终都会通过props传给Detail组件
// props:{a:900}
//第二种写法:props值为布尔值,布尔值为true,则把路由收到的所有params参数通过props传给Detail组件
// props:true
//第三种写法:props值为函数,该函数返回的对象中每一组key-value都会通过props传给Detail组件
props(route){
return {
id:route.query.id,
title:route.query.title
}
}
}
3.指定展示位置
当前A组件代码中要跳转的B组件具体数据展示在A组件中的,如下位置
<router-view></router-view>
4.router-link 的replace和push属性
作用:控制路由跳转时操作浏览器历史记录的模式。
浏览器的历史记录有两种写入方式:分别为push和replace,push是追加历史记录,replace是替换当前记录。路由跳转时候默认为push。
如何开启replace模式:
<router-link replace .......>News</router-link>
5.编程式路由导航
作用:不借助实现路由跳转,让路由跳转更加灵活。与router-link
的replace和push属性有冲突,一般不要同时用。
具体编码(一般用于按钮button中方法,直接放到方法里面):
//$router的两个API
this.$router.push({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.replace({
name:'xiangqing',
params:{
id:xxx,
title:xxx
}
})
this.$router.forward() //前进
this.$router.back() //后退
this.$router.go() //可前进也可后退
注意:
- params 也可以换成query
6.缓存路由组件
作用:让不展示(切换的路由组件就自动销毁了)的路由组件保持挂载,不被销毁。比如一个组件A中的输入框输入完数据后切换到另一个组件,则A组件中输入的数据依旧存在。
缓存一个具体编码:
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
注意:
- News:组件名称。
- include不写则缓存所有组件的数据,一般指出具体的组件名称。
如果要缓存多个不缓存1个则:
List.vue
<router-link :to="`/HomeTop/List/CountVuex?titleA=${id}`">
<button>CountVuex--{{id}}--{{title}}</button>
</router-link>
<router-link :to="`/HomeTop/List/PersionListVuex?titleB=${title}`">
<button>PersionListVuex--{{id}}--{{title}}</button>
</router-link>
//缓存2多个,不缓存1个
<keep-alive :include="['PersionListVuex','CountVuex']" exclude="Biaodan">
<router-view></router-view>
</keep-alive>
注意:
- 当时缓存多个时 include 前加 : 切记切记
- 只是缓存一个时
include="PersionListVuex"
我看网上还有方法是在route index.js 路由中meta中写:
meta: {
keepAlive: true // 需要被缓存
}
然后 :
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
<!-- 这里是会被缓存的视图组件,比如 Biaodan! -->
</router-view>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive">
<!-- 这里是不会被缓存的视图组件,比如PersionListVuex! -->
</router-view>
但是 v-if 为 true 时可以缓存,但是为false 那<router-view>
组件不也就销毁了,那甭说数据点击按钮跳转的组件都没了,数据就更没了,我觉得第二种有问题,所以我目前看来网上这种方法不行。 求大佬指教。
缓存总结:
- keep-alive 不会在函数式组件中正常工作,因为它们没有缓存实例。
- 当匹配条件同时在 include 与 exclude 存在时,以 exclude 优先级最高(当前vue 2.4.2 version)。比如:包含于排除同时匹配到了组件A,那组件A不会被缓存
- 包含在 keep-alive 中,但符合 exclude ,不会调用activated和 deactivated,这个结合第 7 两个新的生命周期钩子
7.两个新的生命周期钩子
作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
具体名字:
- activated路由组件被激活时触发。
- deactivated路由组件失活时触发。
场景:比如一个组件A,组件B。不用路由组件特有的函数会出线,A里面有个定时器,切换到B后,A里面的定时器其实还在运行,本来想的是切换到B后A里面的定时器也要停止,然后切回A后A中定时器在运行。这时候在A组件中用上面两个函数特别合适。
vue所有的生命周期函数:
- nextTick()
- activated()
- deactivated()
- beforeCreate()
- created()
- beforeMount()
- mounted()
- beforeUpdate()
- updated()
- beforeDestroy()
- destroyed()
8.路由器的两种工作模式
对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
index.js具体代码:
export default new VueRouter({
mode:"history", //或者 hash(默认)
routes:[{}]
})
hash模式:
- 地址中永远带着#号,不美观
- 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法
- 兼容性较好
history模式:
- 地址干净,美观
- 兼容性和hash模式相比略差
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题
9.路由守卫
作用:对路由进行权限控制。
分类:全局守卫(前置,后置)、独享守卫(只有前置)、组件内守卫
全局守卫:
写在路由配置export default new VueRouter下面
to:点击后去哪个组件。
from:指的是没点击时当前页面的组件。
next():放行的固定方法。
//全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
console.log('beforeEach',to,from)
if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制
if(localStorage.getItem('school') === 'atguigu'){ //权限控制的具体规则
next() //放行
}else{
alert('暂无权限查看')
// next({name:'guanyu'})
}
}else{
next() //放行
}
})
//全局后置守卫:初始化时执行、每次路由切换后执行
router.afterEach((to,from)=>{
console.log('afterEach',to,from)
if(to.meta.title){
document.title = to.meta.title //修改网页的title
}else{
document.title = 'vue_test'
}
})
meta:路由元信息,这里面原本是空的,可以放一些属性,随便定义(例如 isAuth)通过:
首先在路由component 下面写
routes:[{
path:'/HomeTop/:id/:title', //指定要跳转的路径
name:'jiaogao',//组件路由可以通过路径但是如果比如第3级路由时路径写的比较长,所以可以用名字就行
component:HomeTop, //指定要跳转的组件
meta:{isAuth:true},
children: [{}]
}]
获取isAuth具体值:
to.meta.isAuth
修改网页的名称:
document.title
独享守卫:
判断当前路由是否需要进行权限控制
首先在路由component 下面写
routes:[{
path:'/HomeTop/:id/:title', //指定要跳转的路径
name:'jiaogao',//组件路由可以通过路径但是如果比如第3级路由时路径写的比较长,所以可以用名字就行
component:HomeTop, //指定要跳转的组件
children: [{
name:'aa',
meta:{isAuth:true}
}]
}]
beforeEnter(to,from,next){
console.log('beforeEnter',to,from)
if(to.meta.isAuth){
if(localStorage.getItem('school') === 'haha'){
next()
}else{
alert('暂无权限查看')
}
}else{
next()
}
}
组件内守卫:
进入守卫:通过路由规则,进入该组件前被调用
beforeRouteEnter (to, from, next) {
next(). //放行
}
离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
next(). //放行
}
注意:
- 调用beforeRouteEnter()进入和beforeRouteLeave() 离开一定都要next() 不然不能切换了
10.this.$router
和 this.$route
的理解
this.$router
相当于一个全局的路由对象,包含路由相关的属性、对象 (如 history 对象) 和方法,在任何页面都可以通过 this.$router 调用其方法如 push() 、go() 、resolve() 等。
this.$route
表示当前的路由对象。每一个路由都有一个 route 对象,它是一个局部的对象,可以获取当前路由对应的 name , params, path , query 等属性。