vue-router学习(三) --- 导航守卫

文章目录

  • 全局导航守卫
  • 路由独享导航守卫
  • 组件内的守卫
  • 完整的导航解析流程
  • loadingBar 案例

  1. 全局导航守卫
    • beforeEach
    • beforeResolve
    • afterEach
  2. 路由导航守卫
    • beforeEnter
  3. 组件导航守卫
    • beforeRouteEnter
    • beforeRouteUpdate
    • beforeRouteLeave

全局导航守卫

当一个导航触发时,全局前置守卫按照创建顺序调用。
守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。

参数说明:
to: Route, 即将要进入的目标 路由对象;
from: Route,当前导航正要离开的路由;
next(): 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)next(false): 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from 路由对应的地址。
next('/') 或者 next({ path: '/' }): 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。
 

全局前置守卫
router.beforeEach((to,from,next)=>{
	if(xxxxx){
	next('/login')
	}else{
	next()
	}
})

全局解析守卫
注意:解析守卫刚好会在导航被确认之前、所有组件内守卫和异步路由组件被解析之后调用
router.beforeResolve(()=>{})

全局后置钩子
守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用
router.afterEach((to, from) => {
  sendToAnalytics(to.fullPath)
})

案例

const whileList = ['/']
 
router.beforeEach((to, from, next) => {
    let token = localStorage.getItem('token')
    //白名单 有值 或者登陆过存储了token信息可以跳转 否则就去登录页面
    if (whileList.includes(to.path) || token) {
        next()
    } else {
        next({
            path:'/'
        })
    }
})

路由独享导航守卫

const routes = [
  {
    path: '/users/:id',
    component: UserDetails,
    beforeEnter: (to, from) => {
      // reject the navigation
      return false
    },
  },
]

beforeEnter 守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发

beforeEnter作用的是目标路由对象

组件内的守卫

const UserDetails = {
  template: `...`,
  beforeRouteEnter(to, from) {
    在渲染该组件的对应路由被验证前调用
    不能获取组件实例 `this` !
     因为当守卫执行时,组件实例还没被创建!
  },
  beforeRouteUpdate(to, from) {
    在当前路由改变,但是该组件被复用时调用
     举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1``/users/2` 之间跳转的时候,
     由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
     因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
  },
  beforeRouteLeave(to, from) {
     在导航离开渲染该组件的对应路由时调用
     与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
  },
}

完整的导航解析流程

  1. 导航被触发
  2. 在之前失活的组件触发beforeRouterLeave
  3. 调用全局前置守卫beforeEach
  4. 如果是重用的组件/user/:id,调用beforeRouterUpdate更新组件
  5. 然后执行路由守卫beforeEnter
  6. 解析异步路由组件
  7. 然后执行组件内的beforeRouterEnter
  8. 然后会调用全局解析守卫beforeResolve
  9. 这时候导航已经被确认了
  10. 调用全局后置钩子afterEach
  11. 触发 DOM 更新
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

loadingBar 案例

<template>
    <div class="wraps">
        <div ref="bar" class="bar"></div>
    </div>
</template>
    
<script setup lang='ts'>
import { ref, onMounted } from 'vue'
let speed = ref<number>(1)
let bar = ref<HTMLElement>()
let timer = ref<number>(0)
const startLoading = () => {
    let dom = bar.value as HTMLElement;
    speed.value = 1
    timer.value = window.requestAnimationFrame(function fn() {
        if (speed.value < 90) {
            speed.value += 1;
            dom.style.width = speed.value + '%'
            timer.value = window.requestAnimationFrame(fn)
        } else {
            speed.value = 1;
            window.cancelAnimationFrame(timer.value)
        }
    })
 
}
 
const endLoading = () => {
    let dom = bar.value as HTMLElement;
    setTimeout(() => {
        window.requestAnimationFrame(() => {
            speed.value = 100;
            dom.style.width = speed.value + '%'
        })
    }, 500)
 
}
 
 
defineExpose({
    startLoading,
    endLoading
})
</script>
    
<style scoped lang="less">
.wraps {
    position: fixed;
    top: 0;
    width: 100%;
    height: 2px;
    .bar {
        height: inherit;
        width: 0;
        background: blue;
    }
}
</style>
main.ts
import loadingBar from './components/loadingBar.vue'
const Vnode = createVNode(loadingBar)
render(Vnode, document.body)
console.log(Vnode);
 
router.beforeEach((to, from, next) => {
    Vnode.component?.exposed?.startLoading()
})
 
router.afterEach((to, from) => {
    Vnode.component?.exposed?.endLoading()
})

你可能感兴趣的:(vue-router,vue.js,学习,前端)