Vue Router——路由基础详解(二)
🌟导航守卫(拦截)
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。
这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。
(上图为我看视频时学习截图)
一、全局
全局前置守卫——beforeEach
你可以使用 router.beforeEach
注册一个全局前置守卫:
const router = createRouter({ ... })router.beforeEach((to, from, next) => {console.log("导航守卫to:",to, from,next)console.log("导航守卫from:",from)console.log("导航守卫next:",next)//从1到2 是跳不过去的
if(from.path=='/one'&& to.path=='/two'){next(false);next('/oneone');
}next()
})
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
每个守卫方法接收两个参数:
to
: (要跳转到哪个路由对象)from
: (要离开的路由对象)- next(可选):是一个方法,可以接收参数,这个方法必须调用,如果不使用就跳转不过去,你可以把next看做是一个保安,必须跟next打招呼才能过去
可以返回的值如下:
next():告诉保安要过去,去哪就是to
next(false):不能通过,跳转中断
next('路由'):不让过,可以去其他地方
如果遇到了意料之外的情况,可能会抛出一个 Error
。这会取消导航并且调用 router.onError() 注册过的回调。
全局解析守卫——自学beforeResolve
router.beforeResolve
是获取数据或执行任何其他操作(如果用户无法进入页面时你希望避免执行的操作)的理想位置。
全局后置钩子——自学afterEach
和守卫不同的是,这些钩子不会接受 next
函数也不会改变导航本身:
二、路由独享
在路由配置上定义 beforeEnter
守卫:
const routes = [{path: '/users/:id',component: UserDetails,beforeEnter: (to, from) => {// reject the navigationreturn false},},
]
beforeEnter
守卫 只在进入路由时触发,不会在 params
、query
或 hash
改变时触发。
例如,从 /users/2
进入到 /users/3
或者从 /users/2#info
进入到 /users/2#projects
。
它们只有在 从一个不同的 路由导航时,才会被触发。
beforeEnter也可以传一个函数数组
三、组件内的
<script>
export default {beforeRouteEnter(to, from) {// 在渲染该组件的对应路由被验证前调用// 不能获取组件实例 `this` !// 因为当守卫执行时,组件实例还没被创建!},beforeRouteUpdate(to, from) {// 在当前路由改变,但是该组件被复用时调用// 举例来说,对于一个带有动态参数的路径 `/users/:id`,在 `/users/1` 和 `/users/2` 之间跳转的时候,// 由于会渲染同样的 `UserDetails` 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。// 因为在这种情况发生的时候,组件已经挂载好了,导航守卫可以访问组件实例 `this`},beforeRouteLeave(to, from) {// 在导航离开渲染该组件的对应路由时调用// 与 `beforeRouteUpdate` 一样,它可以访问组件实例 `this`},
}
</script>
🌟路由元信息——meta
将任意信息附加到路由上,如过渡名称、谁可以访问路由等。这些事情可以通过接收属性对象的meta
属性来实现,并且它可以在路由地址和导航守卫上都被访问到。
{path: 'new',component: PostsNew,// 只有经过身份验证的用户才能创建帖子meta: { requiresAuth: true },},//route.meta 方法可获取值
🌟过度动效
路径组件上使用转场,并对导航进行动画处理,你需要使用 <RouterView>插槽
全部过度动效
<script setup>
</script><template><router-view v-slot="{ Component }"><transition name="fade"><component :is="Component" /></transition></router-view></template><style scoped>
/* 淡入淡出效果 */
.fade-enter-active,
.fade-leave-active {transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {opacity: 0;
}/* 横向滑动效果 */
.slide-enter-active,
.slide-leave-active {transition: transform 0.5s ease;position: absolute;width: 100%;
}
.slide-enter-from {transform: translateX(100%);
}
.slide-leave-to {transform: translateX(-100%);
}
</style>
单个路由过度动效
<router-view v-slot="{ Component, route }"><!-- :name="route.meta.transition || 'fade'":根据路由的 meta.transition 字段动态选择动画,默认使用 fade。--><!-- mode="out-in":确保旧组件先离开,新组件再进入,避免布局重叠。--><transition :name="route.meta.transition || 'fade'" ><component :is="Component" /></transition></router-view>
//过度动效{path: '/custom-transition',component: () => import('@/view/one.vue'),meta: { transition: 'fade' },//淡入淡出},{path: '/other-transition',component: () => import('@/view/two.vue'),meta: { transition: 'slide' },//横向滑动},
🌟滚动行为——scrollBehavior
使用前端路由,当切换到新路由时,想要页面滚到顶部,或者是保持原先的滚动位置,就像重新加载页面那样。
注意: 这个功能只在支持 history.pushState 的浏览器中可用。
const router = createRouter({history: createWebHistory(import.meta.env.VITE_APP_ROUTER_PREFIX),routes: constantRoutes,scrollBehavior(to, from, savedPosition) {if (savedPosition) {return savedPosition} else {return { top: 0 }}}
})
浏览器历史导航(前进/后退)
savedPosition
会自动记录离开页面时的滚动位置,此时返回 savedPosition
,页面会滚动到之前的位置。如果是首次打开或者是使用编程式导航(router.push())时savedPosition是undefined会滚动到顶部。
🌟路由懒加载
当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就会更加高效。
Vue Router 支持开箱即用的动态导入,这意味着你可以用动态导入代替静态导入:
// 将
// import UserDetails from './views/UserDetails.vue'
// 替换成
const UserDetails = () => import('./views/UserDetails.vue')const router = createRouter({// ...routes: [{ path: '/users/:id', component: UserDetails }// 或在路由定义里直接使用它{ path: '/users/:id', component: () => import('./views/UserDetails.vue') },],
})
按需加载:Vue Router 只会在第一次进入页面时才会获取这个函数,然后使用缓存数据。
缩短首屏时间:减少初始加载的 JavaScript 文件体积,避免长时间白屏
节省带宽:仅加载用户当前访问的路由资源,减少不必要的网络请求
优化用户体验:尤其适用于大型单页应用(SPA),降低用户等待感知
🌟动态路由
动态路由主要通过两个函数实现。
router.addRoute()
:动态添加新路由,支持嵌套路由扩展。router.removeRoute()
:按名称删除路由,同步清理子路由和别名。
if (useUserStore().roles.length === 0) {// 判断当前用户是否已拉取完user_info信息useUserStore().getInfo().then(() => {usePermissionStore().generateRoutes()//根据用户角色筛选出可访问的路由配置.then((accessRoutes) => {// 根据roles权限生成可访问的路由表accessRoutes.forEach((route) => {if (!isHttp(route.path)) {router.addRoute(route) // 动态添加可访问路由表}})next({ ...to, replace: true }) // hack方法 确保addRoutes已完成})}).catch((err) => {useUserStore().logOut().then(() => {// ElMessage.error(err != undefined ? err : '登录失败')next({ path: '/' })})})}
Vue Router 提供了两个功能来查看现有的路由:
- router.hasRoute():检查路由是否存在。
- router.getRoutes():获取一个包含所有路由记录的数组。