路由守卫的核心作用是在路由跳转过程中执行特定的逻辑(如权限校验、数据预取)
路由 链接到标题
一个路由(route)就是一组映射关系(key - value),多个路由需要路由器(router)进行管理
key是路径,value是组件
安装vue-router,命令:npm i vue-router
const router = new VueRouter({
routes:[
{
path:'/about',
component:About
},
{
path:'/home',
component:Home
}
]
})
//暴露router
export default router
路由组件通常存放在pages文件夹,一般组件通常存放在components文件夹
通过切换,“隐藏”了的路由组件,默认是被销毁掉的,需要的时候再去挂载
每个组件都有自己的$route属性,里面存储着自己的路由信息
<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 class="panel">
<div class="panel-body">
<!-- 指定组件的呈现位置 -->
<router-view></router-view>
</div>
</div>
默认模式:
<!-- 点击后,浏览器历史记录新增一条,可通过「后退」回到上一页 -->
<router-link to="/detail">默认跳转</router-link>
<!-- 点击后,替换当前历史记录,无法通过「后退」回到上一页 -->
<router-link to="/detail" replace>replace 跳转</router-link>
多级路由 链接到标题
routes:[
{
path:'/about',
component:About,
},
{
path:'/home',
component:Home,
children:[ //通过children配置子级路由
{
path:'news', //此处一定不要写:/news
component:News
},
{
path:'message',//此处一定不要写:/message
component:Message
}
]
}
]
//跳转(要写完整路径)
<router-link to="/home/news">News</router-link>
路由传参—query参数 链接到标题
两种方法:
第一种,to变成 :to , 然后参数写在 ? 后面 。 a=${ data.x } 或者传 常量
<router-link :to="`/home/message/detail?id=${m.id}&title=${m.title}`">{{m.title}}</router-link>
<router-link :to="/home/message/detail?id=666&title=你好">跳转</router-link>
第二种,to的对象写法 , 写 path 和 query
<router-link
:to="{
path:'/home/message/detail',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
路由传参—params参数 链接到标题
这个第一步需要先配置路由,使用占位符来接收参数
{
path:'/home',
component:Home,
children:[
{
path:'news',
component:News
},
{
component:Message,
children:[
{
name:'xiangqing',
path:'detail/:id/:title', //使用占位符声明接收params参数
component:Detail
}
]
}
]
}
同样也有两种方法发送:
第一种, 第一种,to变成 :to ,这个不需要❓ a=${ data.x } 或者传 常量
<router-link :to="/home/message/detail/666/你好">跳转</router-link>
<router-link :to="`/home/message/detail/${m.id}/${m.title}`">{{m.title}}</router-link>
<!-- 跳转并携带params参数,to的对象写法, 这里千万不能有path -->
<router-link
:to="{
name:'xiangqing',
params:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
路由接收参数 — 两个方法都一样 链接到标题
$route.query.id
$route.query.title
命名路由–用于简化路由跳转 链接到标题
①给路由命名
{
path:'/demo',
component:Demo,
children:[
{
path:'test',
component:Test,
children:[
{
name:'hello' //给路由命名
path:'welcome',
component:Hello,
}
]
}
]
}
②简化跳转
<!--简化前,需要写完整的路径 -->
<router-link to="/demo/test/welcome">跳转</router-link>
<!--简化后,直接通过名字跳转 -->
<router-link :to="{name:'hello'}">跳转</router-link>
<!--简化写法配合传递参数 -->
<router-link
:to="{
name:'hello',
query:{
id:666,
title:'你好'
}
}"
>跳转</router-link>
路由的props配置—方便收到参数 链接到标题
方便体现在:
// 之前接收参数: // Detail.vue
<template>
<ul>
<li>消息编号:{{$route.params.id}}</li>
<li>消息标题:{{$route.params.title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
mounted() {
// console.log(this.$route)
},
}
</script>
// 使用propos配置 接收参数
<template>
<ul>
<li>消息编号:{{id}}</li>
<li>消息标题:{{title}}</li>
</ul>
</template>
<script>
export default {
name:'Detail',
props:['id','title'],
}
</script>
配置propos有三种方法:
| 写法类型 | 语法示例 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| 对象写法 | props: {a:1, b:'hello'} |
1. 写法最简单;2. 传固定值非常方便 | 1. 只能传静态值,无法获取路由参数;2. 灵活性极低 | 仅需要给路由组件传固定常量的场景 |
| 布尔写法 | props: true |
1. 简洁,自动映射 params 参数;2. 组件解耦(不用写 $route) |
1. 仅支持 params 参数(不支持 query);2. 无法自定义参数名 / 新增额外参数 |
路由用 params 传参(如 /detail/:id),且参数名和组件 props 名一致的场景 |
| 函数写法 | props($route) { return {id: $route.query.id} } |
1. 支持 params/query 任意参数;2. 可自定义参数名、新增额外参数;3. 组件完全解耦 |
1. 写法比前两种稍复杂;2. 需要手动映射参数 | 绝大多数场景(尤其是用 query 传参、需要自定义参数、新增固定值的场景) |
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
缓存路由组件 链接到标题
<keep-alive include="News">
<router-view></router-view>
</keep-alive>
生命周期钩子:
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated路由组件被激活时触发。deactivated路由组件失活时触发。
编程式路由导航–放弃router-link 链接到标题
不借助<router-link> 实现路由跳转,使用router的两个API
//$router的两个API,封装在一个函数里,通过调用函数触发路由跳转
function(){
this.$router.xxx(??)
}
// 操作有
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() //可前进也可后退
优点:
可结合任意事件触发(点击、双击、定时器、接口回调等); 前者只能点击
跳转前可加复杂逻辑(表单验证、权限判断、参数加工)适配复杂业务场景;
支持路由守卫
缺点:
不能用activate-class激活样式
不能重复push到一个路由里面,需要加个判断,不然报错
全局路由守卫 链接到标题
全局守卫直接挂载在 router 实例上,对所有路由跳转生效
beforeEach(to, from, next):最常用。在路由跳转前触发,常用于登录状态校验。beforeResolve(to, from, next):在导航被确认之前,且组件内守卫和异步路由组件被解析之后调用。afterEach(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'
}
})
路由独享守卫 链接到标题
如果你不想全局配置守卫的话,你可以为某些路由单独配置守卫:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
// ...
}
}
]
})
组件内的路由守卫 链接到标题
直接定义在 .vue 组件内部,针对特定组件生效。
beforeRouteEnter:路由进入该组件前调用。此时拿不到组件实例this,因为组件实例还没被创建。该钩子在全局守卫beforeEach之后,全局守卫afterEach之前调用。beforeRouteUpdate:当前路由改变,且该组件被复用时调用(例如/user/1跳转到/user/2)。beforeRouteLeave:导航离开该组件时调用。常用于“离开前未保存”的选择提醒。
//进入守卫:通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
},
//离开守卫:通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
}
路由的hash和history模式的区别 链接到标题
Vue-Router有两种模式:hash模式和history模式。默认的路由模式是hash模式。
1. hash模式 链接到标题
简介: hash模式是开发中默认的模式,它的URL带着一个#,例如:http://www.abc.com/#/vue,它的hash值就是 #/vue。
特点:hash值会出现在URL里面,但是不会出现在HTTP请求中,对后端完全没有影响。所以改变hash值,不会重新加载页面。这种模式的浏览器支持度很好,低版本的IE浏览器也支持这种模式。hash路由被称为是前端路由,已经成为SPA(单页面应用)的标配。
原理: hash模式的主要原理就是onhashchange()事件:
window.onhashchange = function(event){
console.log(event.oldURL, event.newURL);
let hash = location.hash.slice(1);
}
使用onhashchange()事件的好处就是,在页面的hash值发生变化时,无需向后端发起请求,window就可以监听事件的改变,并按规则加载相应的代码。除此之外,hash值变化对应的URL都会被浏览器记录下来,这样浏览器就能实现页面的前进和后退。虽然是没有请求后端服务器,但是页面的hash值和对应的URL关联起来了。
2. history模式 链接到标题
简介: history模式的URL中没有#,它使用的是传统的路由分发模式,即用户在输入一个URL时,服务器会接收这个请求,并解析这个URL,然后做出相应的逻辑处理。
特点: 当使用history模式时,URL就像这样:http://abc.com/user/id。相比hash模式更加好看。但是,history模式需要后台配置支持。如果后台没有正确配置,访问时会返回404。
API: history api可以分为两大部分,切换历史状态和修改历史状态:
- 修改历史状态:包括了 HTML5 History Interface 中新增的
pushState()和replaceState()方法,这两个方法应用于浏览器的历史记录栈,提供了对历史记录进行修改的功能。只是当他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。如果要做到改变url但又不刷新页面的效果,就需要前端用上这两个API。 - 切换历史状态: 包括
forward()、back()、go()三个方法,对应浏览器的前进,后退,跳转操作。
虽然history模式丢弃了丑陋的#。但是,它也有自己的缺点,就是在刷新页面的时候,如果没有相应的路由或资源,就会刷出404来。
如果想要切换到history模式,就要进行以下配置(后端也要进行配置):
const router = new VueRouter({
mode: 'history',
routes: [...]
})
3. 两种模式对比 链接到标题
调用 history.pushState() 相比于直接修改 hash,存在以下优势:
- pushState() 设置的新 URL 可以是与当前 URL 同源的任意 URL;而 hash 只可修改 # 后面的部分,因此只能设置与当前 URL 同文档的 URL;
- pushState() 设置的新 URL 可以与当前 URL 一模一样,这样也会把记录添加到栈中;而 hash 设置的新值必须与原来不一样才会触发动作将记录添加到栈中;
- pushState() 通过 stateObject 参数可以添加任意类型的数据到记录中;而 hash 只可添加短字符串;
- pushState() 可额外设置 title 属性供后续使用。
- hash模式下,仅hash符号之前的url会被包含在请求中,后端如果没有做到对路由的全覆盖,也不会返回404错误;history模式下,前端的url必须和实际向后端发起请求的url一致,如果没有对用的路由处理,将返回404错误。
hash模式和history模式都有各自的优势和缺陷,还是要根据实际情况选择性的使用。
如何获取页面的hash变化 链接到标题
(1)监听$route的变化
// 监听,当路由发生变化的时候执行
watch: {
$route: {
handler: function(val, oldVal){
console.log(val);
},
// 深度观察监听
deep: true
}
},
(2)window.location.hash读取#值
window.location.hash 的值可读可写,读取来判断状态是否改变,写入时可以在不重载网页的前提下,添加一条历史访问记录。
$route 和$router 的区别 链接到标题
- $route 是“路由信息对象”,包括 path,params,hash,query,fullPath,matched,name 等路由信息参数
- $router 是“路由实例”对象包括了路由的跳转方法,钩子函数等
Vue-router跳转和location.href有什么区别 链接到标题
- 使用
location.href= /url来跳转,简单方便,但是刷新了页面; - 使用
history.pushState( /url ),无刷新页面,静态跳转; - 引进 router ,然后使用
router.push( /url )来跳转,使用了diff算法,实现了按需加载,减少了 dom 的消耗。其实使用 router 跳转和使用history.pushState()没什么差别的,因为vue-router就是用了history.pushState(),尤其是在history模式下。
params和query的区别 链接到标题
用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是 this.$route.query.name 和 this.$route.params.name 。
url地址显示:query更加类似于ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
注意:query刷新不会丢失query里面的数据 params刷新会丢失 params里面的数据。