Vue Router 中全局守卫和组件守卫的使用方式及示例
Vue Router 是 Vue.js 官方提供的路由管理器,它可以用来实现单页面应用(SPA)中的前端路由。在 Vue Router 中可以定义多个路由,每个路由都映射到一个组件,当用户访问对应的路由时,会加载对应的组件并显示在页面上。
在 Vue Router 中,路由配置是一个数组,里面包含了多个路由对象。每个路由对象包含了以下属性:
path
:表示当前路由匹配的 URL 路径。可以是一个字符串,例如'/home'
,也可以是一个包含动态参数的路径,例如'/user/:id'
,动态参数可以通过$route.params
访问;name
:路由的名称,用来在程序中标识路由。名称必须是唯一的,不能与其他路由重名;component
:路由对应的组件。可以是一个引入的组件对象,例如import Home from './views/Home.vue'
,也可以是一个函数,例如() => import('./views/Home.vue')
,用于按需加载组件;meta
:路由的元数据,用来存储一些额外信息,例如页面标题、页面描述等。
在 Vue Router 中,路由配置通常是在一个单独的文件中定义,例如 router.js
。在这个文件中,我们需要先引入 Vue 和 Vue Router,并创建一个新的 Router 实例,然后将路由配置传递给 Router 实例的 routes
属性。最后,我们需要将 Router 实例导出,以便在应用中使用。
下面是一个简单的路由配置示例:
import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import About from './views/About.vue'
import User from './views/User.vue'
Vue.use(Router)
export default new Router({
routes: [
{ path: '/', redirect: '/home' },
{ path: '/home', name: 'home', component: Home },
{ path: '/about', name: 'about', component: About },
{ path: '/user/:id', name: 'user', component: User },
{ path: '*', redirect: '/home' }
]
})
在上面的示例中,我们创建了一个新的 Router 实例,并将路由配置传递给了 routes
属性。这个路由配置包含了四个路由对象,分别对应了 /home
、/about
和 /user/:id
三个路径,以及一个通配符路径 '*'
,用于匹配所有未定义的路径。其中,redirect
属性表示重定向到其他路由。
在 Vue 应用中,我们可以通过 router-link
组件来实现路由的跳转。这个组件可以接受一个 to
属性,用来指定要跳转的路由路径。例如:
Home
About
User
除了使用 router-link
组件来实现路由跳转外,我们还可以在组件中使用 this.$router
和 this.$route
来访问 Router 实例和当前路由信息。
例如,在一个组件的方法中,我们可以通过以下方式来实现路由跳转:
this.$router.push('/home')
this.$router.push({ name: 'about' })
this.$router.push({ path: '/user/123' })
在上面的代码中,我们使用了 $router.push
方法来实现路由的跳转。这个方法接受一个路由描述符作为参数,可以是一个字符串路径,也可以是一个对象,包含了路径、名称、参数等信息。通过这种方式,我们可以动态地修改路由,并实现页面跳转。
除了 $router
和 $route
,我们还可以使用路由守卫来实现更复杂的路由控制。在 Vue Router 中,路由守卫分为全局守卫和组件守卫两种类型。全局守卫可以监听整个路由的生命周期,包括路由的导航、组件的激活和销毁等;而组件守卫则只监听当前组件的生命周期。
组件守卫
在 Vue Router 中,组件守卫是一种用来监听组件生命周期的钩子函数,可以在路由切换的过程中进行一些处理。组件守卫包括 beforeRouteEnter
、beforeRouteUpdate
和 beforeRouteLeave
三个钩子函数,分别对应组件的进入、更新和离开时调用。
具体来说,这三个组件守卫的作用分别如下:
beforeRouteEnter(to, from, next)
:在组件被激活之前调用。这个钩子函数无法访问组件实例,因为在此时组件实例尚未被创建。但是我们可以通过传递一个回调函数next
,在组件实例创建之后再进行一些操作。这个回调函数可以接受一个组件实例作为参数,可以用来进行一些异步操作,例如加载数据。beforeRouteEnter(to, from, next) { // 无法访问组件实例 next(vm => { // 在组件实例创建之后调用 // 可以访问组件实例 vm.loadData() }) }
beforeRouteUpdate(to, from, next)
:在组件复用时调用。这个钩子函数可以访问组件实例,可以根据路由参数的变化,更新组件内部的状态。注意,如果组件在路由切换时不需要重新渲染,就不会触发这个钩子函数。beforeRouteUpdate(to, from, next) { if (to.params.id !== from.params.id) { // 更新组件内部的状态 this.loadData() } next() }
beforeRouteLeave(to, from, next)
:在组件被离开之前调用。这个钩子函数可以用来进行一些确认操作,例如弹出对话框。注意,如果我们要在这个钩子函数中进行异步操作,必须在next
回调函数中进行,否则路由切换会被阻塞。beforeRouteLeave(to, from, next) { if (this.isDirty) { if (confirm('您还有未保存的内容,确定要离开吗?')) { next() } else { next(false) } } else { next() } }
需要注意的是,组件守卫只对当前组件有效,不会影响其他组件。如果需要在整个应用程序中进行一些操作,可以使用全局守卫。另外,在使用组件守卫时,我们还可以通过在路由配置中添加 meta
字段,来传递一些额外的信息。例如:
const routes = [
{
path: '/user/:id',
component: User,
meta: { requiresAuth: true }
}
]
在这个例子中,我们在路由配置中添加了一个 meta
字段,表示这个路由需要进行身份验证。接下来,在组件守卫中就可以通过访问 to.meta.requiresAuth
来获取这个信息了:
beforeRouteEnter(to, from, next) {
if (to.meta.requiresAuth && !auth.loggedIn()) {
next('/login')
} else {
next()
}
}
在这个例子中,如果当前路由需要进行身份验证,但是用户没有登录,就会被重定向到登录页面。
最后,需要注意的是,组件守卫和全局守卫一样,也可以通过返回一个 Promise 对象来进行异步操作。如果在守卫中返回了一个 Promise,Vue Router 就会等待这个 Promise 对象解决之后再进行路由切换。例如:
beforeRouteEnter(to, from, next) {
return axios.get('/user/' + to.params.id).then(response => {
next(vm => {
vm.user = response.data
})
})
}
在这个例子中,我们通过 axios 发送了一个 GET 请求,来加载用户的数据。由于这个请求是异步的,因此我们在组件守卫中返回了一个 Promise 对象,来告诉 Vue Router 等待请求完成之后再进行路由切换。
全局守卫
Vue Router 的全局守卫是指在整个路由系统中都起作用的路由守卫。全局守卫包括了三个函数:
beforeEach
beforeResolve
afterEach
beforeEach
beforeEach
是最常用的全局守卫,它会在每次路由跳转之前调用。beforeEach
接收三个参数:
to
:即将跳转的路由信息对象from
:当前的路由信息对象next
:一个函数,用于控制路由跳转行为
在 beforeEach
中,我们可以根据路由信息对象来判断用户是否有权限访问某个页面,或者是否需要进行登录等操作。如果需要进行操作,可以调用 next
函数来进行路由跳转。
下面是一个例子,当用户访问 /dashboard
页面时,需要进行身份验证:
router.beforeEach((to, from, next) => {
if (to.path === '/dashboard' && !auth.loggedIn()) {
next('/login')
} else {
next()
}
})
在这个例子中,如果用户访问的是 /dashboard
页面,但是用户没有登录,则会被重定向到登录页面。
beforeResolve
beforeResolve
与 beforeEach
类似,它也是在路由跳转之前调用,但是它会在 beforeEach
之后调用。在 beforeResolve
中,我们可以进行一些异步操作,例如加载数据等。
afterEach
afterEach
是在路由跳转之后调用的函数,它没有接收 next
函数。afterEach
主要用于处理一些全局的 UI 交互,例如设置页面标题等。
下面是一个例子,当用户访问成功时,设置页面标题:
router.afterEach((to, from) => {
document.title = to.meta.title || 'My App'
})
在这个例子中,如果在路由配置中设置了 meta.title
,则会设置页面标题为该值,否则设置为默认值 My App
。
需要注意的是,全局守卫是在整个路由系统中都起作用的,因此需要谨慎使用。如果在全局守卫中进行了复杂的逻辑操作,可能会影响整个应用的性能。建议在使用全局守卫时,根据具体场景进行判断,避免不必要的性能损失。
此处评论已关闭