>[success] # 路由守卫
* 从路由`4.x` 开始已经可以不使用`next` 参数 以前使用`next` 参数需要注意调用次数
~~~
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// 如果用户未能验证身份,则 `next` 会被调用两次
next()
})
~~~
~~~
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
~~~
* 从`4.x` 开始只要去指定返回值即可对应跳转路由
* * 1.false: 不进行导航
* * 2.undefined或者不写返回值和返回值为`true`: 进行默认导航
* * 3.字符串: 路径, 跳转到对应的路径中
* * 4.对象: 类似于 router.push({path: "/login", query: ....})
~~~
router.beforeEach((to) => {
console.log(to.path)
if (to.path === '/home') {
return { path: '/about', query: { age: '123' } } // 可以不在使用next形式
}
})
~~~
>[info] ## 关于路由守卫
1. `vuerouter` 一套钩子来触发路由在不同阶段触发的函数
2. 导航守卫分成三大块**全局守卫,路由独享守卫,组件内守卫**
* **全局守卫**顾名思义所有路由在进入跳转的时候都会触发,整个全局守卫分为三个阶段依次是`beforeEach`、`beforeResolve`、`afterEach`
* **路由独享守卫**,只在定义路由中使用它有一个阶段`beforeEnter`
* **组件内守卫**,只在组件中触发的路由内容它有三个阶段依次`beforeRouteEnter`、`beforeRouteUpdate`、`beforeRouteLeave`
3. 关于守卫中回调参数
* to: Route: 即将要进入的目标 路由对象
* from: Route: 当前导航正要离开的路由
>[danger] ##### 全局守卫 -- 全局前置守卫(beforeEach)
1. **全局前置守卫**在路由刚开始触发且还未进入,路由对应的组件中,简单的理解最早触发,但是触发时候没有任何组件一类的加载,正因为如此适合做登陆判断逻辑
~~~
const router = createRouter({ ... })
router.beforeEach(async (to, from) => {
if (
// 检查用户是否已登录
!isAuthenticated &&
// ❗️ 避免无限重定向
to.name !== 'Login'
) {
// 将用户重定向到登录页面
return { name: 'Login' }
}
})
~~~
* 在router 3.x 时候一般是这么写现在不推荐了
~~~
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
~~~
>[danger] ##### 全局守卫 -- 全局解析守卫(beforeResolve )
1. 在导航被确认之前,同时在路由独享守卫和所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用,实际开发中没太用过
>[danger] ##### 全局守卫 -- 全局后置钩子(afterEach)
1. 在所有路由的生命周期结束后调用,使用场景它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。或者当我们在加载后台数据的时候经常会做一个蒙版这个蒙版上会有一个加载的转圈的团,`afterEach`是整个路由结束阶段,因此也可以理解成是整个组件加载完阶段,所以在这个时候控制蒙版消失最好
>[danger] ##### 路由独享守卫 -- beforeEnter
1. `beforeEnter`守卫**只在进入路由时触发**,不会在`params`、`query`或`hash`改变时触发。例如,从`/users/2`进入到`/users/3`或者从`/users/2#info`进入到`/users/2#projects`。它们只有在**从一个不同的**路由导航时,才会被触发。
~~~
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
~~~
* 除了支持函数也支持数组的形式
~~~
function removeQueryParams(to) {
if (Object.keys(to.query).length)
return { path: to.path, query: {}, hash: to.hash }
}
function removeHash(to) {
if (to.hash) return { path: to.path, query: to.query, hash: '' }
}
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: [removeQueryParams, removeHash],
},
{
path: '/about',
component: UserDetails,
beforeEnter: [removeQueryParams],
},
]
~~~
>[info] ## 组件路由守卫
~~~
const UserDetails = {
template: `...`,
beforeRouteEnter(to, from) {
// 在渲染该组件的对应路由被验证前调用
// 不能获取组件实例 `this` !
// 因为当守卫执行时,组件实例还没被创建!
},
beforeRouteUpdate(to, from) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,
// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`
},
beforeRouteLeave(to, from) {
// 在导航离开渲染该组件的对应路由时调用
// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`
},
}
~~~
~~~
1.可以通过传一个回调给 next来访问组件实例。在导航被确认的时候执行回
调,并且把组件实例作为回调方法的参数。
2.注意 beforeRouteEnter 是支持给 next 传递回调的唯一守卫。对于
beforeRouteUpdate 和 beforeRouteLeave 来说,this 已经可用了,所以不
支持传递回调,因为没有必要了。
beforeRouteEnter (to, from, next) {
next(vm => {
// 通过 `vm` 访问组件实例
})
}
~~~
1. **导航完成之后获取**:先完成导航,然后在接下来的组件生命周期钩子中获取数据。在数据获取期间显示“加载中”之类的指示。
2. 在**导航完成之前获取**:导航完成前,在路由进入的守卫中获取数据,在数据获取成功后执行导航
也就是说你可以选择在vue 生命周期中获取请求接口数据,也可以在组件的路由生命周期去获取数据这完全是看个人习惯 [链接](https://router.vuejs.org/zh/guide/advanced/data-fetching.html#%E5%9C%A8%E5%AF%BC%E8%88%AA%E5%AE%8C%E6%88%90%E5%89%8D%E8%8E%B7%E5%8F%96%E6%95%B0%E6%8D%AE)
>[info] ## 路由组件完整周期
1. 导航被触发。
2. 在失活的组件里调用`beforeRouteLeave`守卫。
3. 调用全局的`beforeEach`守卫。
4. 在重用的组件里调用`beforeRouteUpdate`守卫(2.2+)。
5. 在路由配置里调用`beforeEnter`。
6. 解析异步路由组件。
7. 在被激活的组件里调用`beforeRouteEnter`。
8. 调用全局的`beforeResolve`守卫(2.5+)。
9. 导航被确认。
10. 调用全局的`afterEach`钩子。
11. 触发 DOM 更新。
12. 调用`beforeRouteEnter`守卫中传给`next`的回调函数,创建好的组件实例会作为回调函数的参数传入。
- 官网给的工具
- 声明vue2 和 vue3
- 指令速览
- Mustache -- 语法
- v-once -- 只渲染一次
- v-text -- 插入文本
- v-html -- 渲染html
- v-pre -- 显示原始的Mustache标签
- v-cloak -- 遮盖
- v-memo(新)-- 缓存指定值
- v-if/v-show -- 条件渲染
- v-for -- 循环
- v-bind -- 知识
- v-bind -- 修饰符
- v-on -- 点击事件
- v-model -- 双向绑定
- 其他基础知识速览
- 快速使用
- 常识知识点
- key -- 作用 (后续要更新)
- computed -- 计算属性
- watch -- 侦听
- 防抖和节流
- vue3 -- 生命周期
- vue-cli 和 vite 项目搭建方法
- vite -- 导入动态图片
- 组件
- 单文件组件 -- SFC
- 组件通信 -- porp
- 组件通信 -- $emit
- 组件通信 -- Provide / Inject
- 组件通信 -- 全局事件总线mitt库
- 插槽 -- slot
- 整体使用案例
- 动态组件 -- is
- keep-alive
- 分包 -- 异步组价
- mixin -- 混入
- v-model-- 组件
- 使用计算属性
- v-model -- 自定义修饰符
- Suspense -- 实验属性
- Teleport -- 指定挂载
- 组件实例 -- $ 属性
- Option API VS Composition API
- Setup -- 组合API 入口
- api -- reactive
- api -- ref
- 使用ref 和 reactive 场景
- api -- toRefs 和 toRef
- api -- readonly
- 判断性 -- API
- 功能性 -- API
- api -- computed
- api -- $ref 使用
- api -- 生命周期
- Provide 和 Inject
- watch
- watchEffect
- watch vs. watchEffect
- 简单使用composition Api
- 响应性语法糖
- css -- 功能
- 修改css -- :deep() 和 var
- Vue3.2 -- 语法
- ts -- vscode 配置
- attrs/emit/props/expose/slots -- 使用
- props -- defineProps
- props -- defineProps Ts
- emit -- defineEmits
- emit -- defineEmits Ts
- $ref -- defineExpose
- slots/attrs -- useSlots() 和 useAttrs()
- 自定义指令
- Vue -- 插件
- Vue2.x 和 Vue3.x 不同点
- $children -- 移除
- v-for 和 ref
- attribute 强制行为
- 按键修饰符
- v-if 和 v-for 优先级
- 组件使用 v-model -- 非兼容
- 组件
- h -- 函数
- jsx -- 编写
- Vue -- Router
- 了解路由和vue搭配
- vueRouter -- 简单实现
- 安装即使用
- 路由懒加载
- router-view
- router-link
- 路由匹配规则
- 404 页面配置
- 路由嵌套
- 路由组件传参
- 路由重定向和别名
- 路由跳转方法
- 命名路由
- 命名视图
- Composition API
- 路由守卫
- 路由元信息
- 路由其他方法 -- 添加/删除/获取
- 服务器配置映射
- 其他
- Vuex -- 状态管理
- Option Api -- VUEX
- composition API -- VUEX
- module -- VUEX
- 刷新后vuex 数据同步
- 小技巧
- Pinia -- 状态管理
- 开始使用
- pinia -- state
- pinia -- getter
- pinia -- action
- pinia -- 插件 ??
- Vue 源码解读
- 开发感悟
- 练手项目