路由守卫
情况一: 在使用vue-router开发的项目中,一般情况下不同路由之间的切换会将离开的路由组件卸载,进入的路由组件挂载。这种情况下我们可通过vue的声明周期进行一些页面的逻辑操作。但是如果有些情况下应用为提高用户体验减少卸载频率或者保存离开组件的活跃性,使用<keep-alive>
组件包裹<router-view/>
后路由的切换就吧会卸载离开的组件了这时,如果你的组件需要在路由进入或离开时进行一些操作修改组件自身的数据DOM编程等,就不能再依靠vue的声明周期了。这种情况下请使用组件内的路由守卫。
语法: 在组件内部配置路由守卫;
beforeRouteEnter
路由组件将要进入
beforeRouteUpdate
(2.2 新增) 路由组件将要更新,例:在 /music/:id 中 /music/10086 -> /music/10010
beforeRouteLeave
路由组件将要离开
代码:
export default {
props: ['id'],
data() {
return {
musicUrl: ''
}
},
beforeRouteEnter (to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
console.log(undefined)
},
beforeRouteUpdate (to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave (to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
注意: 组件独享的路由守卫方法都包含三个参数to from next
to : location
本次路由导航跳转的目标路由信息对象
from : location
本次路由导航从哪个路由信息对象跳转而来
next : function
该方法是否允许本次路由跳转
// 注意 只有beforeRouteEnter 的next方法可以接受一个回调函数,
// 该回调函数接收当前路由组件实例对象作为参数,我们可以通过该参数操作当前组件
beforeRouteEnter(to, from, next) {
console.log(to , from)
console.log('组件将要进入,这是组件实例还不存在',this)
next(vm => {
fetch(`/song/url?id=${vm.id}`)
.then((res) => res.json())
.then(({ data }) => {
//真实开发中这里要判断数据是否请求成功
console.log(data[0]);
// 把歌曲的数据赋值给data
vm.musicUrl = data[0]?.url
});
}) // 允许路由跳转
}
情况二:在使用vue-router开发的项目中,一般情况下不同路由之间的切换会将离开的路由组件卸载,进入的路由组件挂载。这种情况下我们可通过vue的生命周期进行一些页面的逻辑操作。但是如果有些情况下应用为提高用户体验减少卸载频率或者保存离开组件的活跃性,使用<keep-alive>
组件包裹<router-view>
后路由的切换就不会卸载离开的组件了,如果你的组件需要在路由进入或离开时进行一些操作不需要修改组件自身的状态只是判断是否允许本次路由的跳转等。这种情况下请使用路由独享守卫。
语法: 在Router.routes配置对象中配置路由守卫;
beforeEnter(to, from, next)
当路由将要导航至当前路由时触发
代码:
const routes = [
{
path: '/',
component: Home
},
{
path: '/discover',
component: () => import('../views/Discover')
},
{
path: '/mine',
component: () => import('../views/Mine'),
//路由独享守卫
beforeEnter(to, from, next) {
// 因为这个守卫没有任何DOM操作或者对组件自身状态进行读写
// 这样的守卫就可以作为路由独享守卫
// 正确的做法存在cookie storage中
if (localStorage.getItem("user")) {
next();
} else {
// 这里吗没有this, next接收一个回调函数,在回调函数中跳转
// 下面的写法进入了个人页面,又从个人页面重定向到登录,这样可能会造成一些不必要的bug
// next((vm) => {
// vm.$router.replace('/landr')
// });
next({name:'login',params:{to}}); //阻止本次跳转,直接导航到指定路由
}
}
},
{
path: '/landr', // login an register
component: () => import('../views/loginanregister/LoginAndRegister'),
children: [
{
name:'login',
path: 'login',
component: () => import('../views/loginanregister/Login')
},
{
path: 'register',
component: () => import('../views/loginanregister/Register')
}
]
}
]
情况三: 全局路由守卫,当应用中有多个路由都需要进行相同逻辑的路由守卫判断时,并且该逻辑操作中不需要直接操作组件DOM或组件组件的状态这是就可以使用全局路由守卫(全局守卫最常见的应用就是登陆验证)
语法: 在Router对象实例完成后,配置Router实例对象自身的实例路由守卫方法;
router.beforeEach(to,from,next)
全局前置守卫。
router.beforeResolve(to,from,next)
全局前置守卫,在beforeEach触发之后。
router.afterEach(to, from)
全局后置守卫,该守卫路由已经离开时触发,该守卫没有next以为跳转已经发生。
代码:
import Vue from 'vue'
import Router from 'vue-router'
import Home from '../views/Home'
Vue.use(Router)
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/discover',
name: 'Discover',
component: () => import('../views/Discover')
},
{
path: '/mine',
name: 'Mine',
component: () => import('../views/Mine'),
},
{
path: '/landr', // login an register
component: () => import('../views/loginanregister/LoginAndRegister'),
children: [
{
name: 'login',
path: 'login',
component: () => import('../views/loginanregister/Login')
},
{
path: 'register',
component: () => import('../views/loginanregister/Register')
}
]
}
]
const router = new Router({
routes,
linkExactActiveClass: 'active'
})
// 路由的全局守卫所有的路由跳转,都会调用该守卫
// 全局路由守卫也是Vue router应用中,最适合做登录验证的地方
router.beforeEach((to, from, next) => {
if(to.name === "Mine" || to.name === "Discover") {
// 因为这个守卫没有任何DOM操作或者对组件自身状态进行读写
// 这样的守卫就可以作为路由独享守卫
// 正确的做法存在cookie storage中
if (localStorage.getItem("user")) {
next();
} else {
next({ name: 'login', params: { to } }); //阻止本次跳转,直接导航到指定路由
}
}else {
next()
}
})
export default router