文章目录
- 生命周期钩子
- 案例实现
- 总结
- 路由守卫
- 全局路由守卫
- 独享守卫
- 组件内守卫
- 总结
- 路由器的两种工作模式
- 总结
生命周期钩子
我们在News组件列表中的第一行加一个渐变文字。同时原来的路由缓存功能也要保存。
案例分析:
我们实现这个渐变的效果,是使用周期定时器Window setInterval() 方法完成:
现在有一个问题就是当我们跳转路由的时候,因为News路由被缓存了不会被销毁,执行不了beforeDestroy,也就是说我们即使没有呈现News组件,这个定时器也一直在被调用,显示这是很浪费资源的。
那我们如何关闭我们的定时器呢?这个时候就要借助路由中两个独特的生命周期钩子:
- activated
- deactivated
案例实现
News.vue:
<template>
<ul>
<li :style="{opacity}">欢迎学习Vue</li>
<li>news001 <input type="text"></li>
<li>news002 <input type="text"></li>
<li>news003 <input type="text"></li>
</ul>
</template>
<script>
export default {
name:'News',
data() {
return {
opacity:1
}
},
/* beforeDestroy() {
console.log('News组件即将被销毁了')
clearInterval(this.timer)
}, */
/* mounted(){
this.timer = setInterval(() => {
console.log('@')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
}, */
activated() {
console.log('News组件被激活了')
this.timer = setInterval(() => {
console.log('@')
this.opacity -= 0.01
if(this.opacity <= 0) this.opacity = 1
},16)
},
deactivated() {
console.log('News组件失活了')
clearInterval(this.timer)
},
}
</script>
总结
两个新的生命周期钩子
- 作用:路由组件所独有的两个钩子,用于捕获路由组件的激活状态。
- 具体名字:
activated
路由组件被激活时触发。deactivated
路由组件失活时触发。
路由守卫
路由守卫的作用就是对路由进行权限控制
Vue中有三种路由守卫:
- 全局守卫
- 全局前置守卫
- 全局后置守卫
- 独享守卫
- 组件内守卫
全局路由守卫
例如现在我们有一个需求当跳转News、Message路由的时候如果学校名不是atguigu那么就要显示一个弹窗:
想要实现这个功能我们就需要借助全局前置守卫!
全局前置守卫:初始化时执行、每次路由切换前执行
router.beforeEach((to,from,next)=>{
})
每次在初始化、路由切换前都会执行其中的回调函数。这个函数接受三个参数:
- to:目的地路由
- from:出发点路由
- next:只有在调用next()才会放行
我们页面初始化的时候可以看看它们的结构
这样我们就可以实现我们上述的功能了
但是我们发现这么写也不太完美,假如我们要进行权限鉴定的路由一多,那么这里的if语句里面就要写一长串代码。
那么我们可以这么改进:我们在每一个路由里面都加上一个特殊的属性用来标识这个路由是否需要进行鉴权。这个特殊的属性我们可以往路由对象的meta(路由元信息
)里放:
这是专门设计用来给程序员存放一些个人数据的地方(不能直接挂载在路由队对象上)
然后我们升级一下我们的代码:
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{isAuth:true,title:'消息'},
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
meta:{isAuth:true,title:'详情'},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// props:true
//props的第三种写法,值为函数
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
]
}
]
}
]
})
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log('前置路由守卫',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
export default router
接下来我们说说全局后置守卫。
我们现在有一个新需求就是在我们跳转路由的时候标签页的名字也要跟着变化
代码实现:
// 该文件专门用于创建整个应用的路由器
import VueRouter from 'vue-router'
//引入组件
import About from '../pages/About'
import Home from '../pages/Home'
import News from '../pages/News'
import Message from '../pages/Message'
import Detail from '../pages/Detail'
//创建并暴露一个路由器
const router = new VueRouter({
routes:[
{
name:'guanyu',
path:'/about',
component:About,
meta:{title:'关于'}
},
{
name:'zhuye',
path:'/home',
component:Home,
meta:{title:'主页'},
children:[
{
name:'xinwen',
path:'news',
component:News,
meta:{isAuth:true,title:'新闻'}
},
{
name:'xiaoxi',
path:'message',
component:Message,
meta:{isAuth:true,title:'消息'},
children:[
{
name:'xiangqing',
path:'detail',
component:Detail,
meta:{isAuth:true,title:'详情'},
//props的第一种写法,值为对象,该对象中的所有key-value都会以props的形式传给Detail组件。
// props:{a:1,b:'hello'}
//props的第二种写法,值为布尔值,若布尔值为真,就会把该路由组件收到的所有params参数,以props的形式传给Detail组件。
// props:true
//props的第三种写法,值为函数
props($route){
return {
id:$route.query.id,
title:$route.query.title,
a:1,
b:'hello'
}
}
}
]
}
]
}
]
})
//全局前置路由守卫————初始化的时候被调用、每次路由切换之前被调用
router.beforeEach((to,from,next)=>{
console.log('前置路由守卫',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
})
//全局后置路由守卫————初始化的时候被调用、每次路由切换之后被调用
router.afterEach((to,from)=>{
console.log('后置路由守卫',to,from)
document.title = to.meta.title || '硅谷系统'
})
export default router
注意:
- 全局后置路由守卫初始化的时候被调用、每次路由切换之后被调用
- 全局后置路由守卫中的回调函数没有next参数。(跳转都跳转完了,也就没有放行这个说法了)
独享守卫
某一个路由独享的守卫
它写在路由对象的里面:
独享守卫只有前置,没有后置!但是它可以和全局后置守卫配合。
组件内守卫
我们直接来看一个组件内守卫的代码:
About组件
<template>
<h2>我是About的内容</h2>
</template>
<script>
export default {
name:'About',
/* beforeDestroy() {
console.log('About组件即将被销毁了')
},*/
/* mounted() {
console.log('About组件挂载完毕了',this)
window.aboutRoute = this.$route
window.aboutRouter = this.$router
}, */
mounted() {
// console.log('%%%',this.$route)
},
//通过路由规则,进入该组件时被调用
beforeRouteEnter (to, from, next) {
console.log('About--beforeRouteEnter',to,from)
if(to.meta.isAuth){ //判断是否需要鉴权
if(localStorage.getItem('school')==='atguigu'){
next()
}else{
alert('学校名不对,无权限查看!')
}
}else{
next()
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave (to, from, next) {
console.log('About--beforeRouteLeave',to,from)
next()
}
}
</script>
注意点:
-
什么叫通过路由规则?
说的直白一点,像这样直接呈现就没有通过路由规则:
我们通过点击导航项进入才叫通过路由规则。 -
beforeRouteLeave离开该组件时被调用,它跟后置守卫有些不同。比如说你现在处在About组件中,只有你在点击导航进入其他组件的时候,这个方法才会被调用。
总结
路由守卫
-
作用:对路由进行权限控制
-
分类:全局守卫、独享守卫、组件内守卫
-
全局守卫:
//全局前置守卫:初始化时执行、每次路由切换前执行 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' } })
-
独享守卫:
beforeEnter(to,from,next){ console.log('beforeEnter',to,from) if(to.meta.isAuth){ //判断当前路由是否需要进行权限控制 if(localStorage.getItem('school') === 'atguigu'){ next() }else{ alert('暂无权限查看') // next({name:'guanyu'}) } }else{ next() } }
-
组件内守卫:
//进入守卫:通过路由规则,进入该组件时被调用 beforeRouteEnter (to, from, next) { }, //离开守卫:通过路由规则,离开该组件时被调用 beforeRouteLeave (to, from, next) { }
路由器的两种工作模式
我们发现每当我们在使用路由的时候,我们的地址栏里面总会有一个#
:
所以这玩意到底是个啥?
我们把这个#
叫做hash
我们把路径中从#
开始到结尾的这一部分叫做hash值
:
hash值最大的特点就是它不会随着http请求发给服务器
我们看个例子就懂了,以下的两个页面是一样的:
我们的路由器一共有两种工作模式:
- hash工作模式:带有hash值
- history工作模式:不带有hash值
除了这个区别这两种模式的兼容性也有差别。
我们在使用history模式进行项目上线的时候,易发生404错误:
我们在点击导航切换路由的时候是没有发送网络请求的,如果此时我们刷新一下,他就回去向服务器请求这个地址,但是服务器压根就没有在这个地址放任何东西,所以就会造成404的错误:
我们解决这个问题需要依赖后端为我们处理请求来消除这个问题,如果是使用nodejs写的后端,我们可以借助一个中间件专门解决这个问题:
总结
路由器的两种工作模式
- 对于一个url来说,什么是hash值?—— #及其后面的内容就是hash值。
- hash值不会包含在 HTTP 请求中,即:hash值不会带给服务器。
- hash模式:
- 地址中永远带着
#
号,不美观 。 - 若以后将地址通过第三方手机app分享,若app校验严格,则地址会被标记为不合法。
- 兼容性较好。
- 地址中永远带着
- history模式:
- 地址干净,美观 。
- 兼容性和hash模式相比略差。
- 应用部署上线时需要后端人员支持,解决刷新页面服务端404的问题。