文章目录
- 1. Vue Router 的介绍
- 2. Vue Router 的安装和使用
- 2.1. 安装
- 2.2. 使用
- 3. Vue Router 的路由配置和参数传递
- 3.1. 路由配置
- 3.2. 参数传递
- 3.2.1. props
- 3.2.2. query
- 3.3. 访问路由参数
- 4. Vue Router 的动态路由和嵌套路由
- 4.1. 动态路由
- 4.2. 嵌套路由
- 5. 路由重定向
- 6. Vue Router 的导航守卫和跳转控制
- 6.1. 全局导航守卫
- 6.1.1. 全局前置守卫(beforeEach)
- 6.1.2. 全局解析守卫(beforeResolve)
- 6.1.3. 全局后置钩子(afterEach)
- 6.2. 路由独享的导航守卫(beforeEnter)
- 6.3. 组件内的导航守卫
1. Vue Router 的介绍
Vue Router 是 Vue.js 官方的路由管理器。它和 Vue.js 的核心深度集成,可以轻松地构建单页面应用程序。Vue Router 允许我们在应用程序中定义路由,然后根据 URL 来匹配路由,并渲染对应的组件。
Vue Router 的核心概念包括路由、路由器、路由视图和导航守卫。
- 路由:指 URL 和组件之间的映射关系
- 路由器:指管理所有路由的实例
- 路由视图:指根据 URL 匹配到的组件
- 导航守卫:指在路由切换时进行的一些处理操作
2. Vue Router 的安装和使用
2.1. 安装
// npm
npm install vue-router@4// yarn
yarn add vue-router@4
2.2. 使用
在 Vue Router 中,我们可以使用 VueRouter
类来创建一个路由器实例,并使用 router-link
和 router-view
组件来定义路由链接和路由视图。
import { createApp } from 'vue'
import { createRouter, createWebHistory } from 'vue-router'
import Home from './components/Home.vue'
import About from './components/About.vue'const router = createRouter({history: createWebHistory(),routes: [{ path: '/', component: Home },{ path: '/about', component: About }]
})const app = createApp({})app.use(router)app.mount('#app')
在上面的例子中,我们使用 createRouter
函数创建了一个路由器实例,并使用 createWebHistory
函数来创建一个基于浏览器历史记录的路由模式。然后,我们定义了两个路由,分别对应 /
和 /about
路径。除了上面这种全局创建之外,更推荐的做法是创建一个 router.js 或 router/index.js 文件。
在模板中,我们可以使用 router-link
组件来定义路由链接,例如:
<template><div><!--使用 router-link 组件进行导航 --><!--通过传递 `to` 来指定链接 --><!--`<router-link>` 将呈现一个带有正确 `href` 属性的 `<a>` 标签--><router-link to="/">Home</router-link><router-link to="/about">About</router-link></div>
</template>
在上面的例子中,我们使用 router-link
组件来定义 /
和 /about
两个路由链接。当用户点击链接时,Vue Router 会根据链接的 to
属性来匹配路由,并渲染对应的组件。
在路由视图中,我们可以使用 router-view
组件来渲染路由组件,例如:
<template><div><!-- 路由出口 --><!-- 路由匹配到的组件将渲染在这里 --><router-view></router-view></div>
</template>
在上面的例子中,我们使用 router-view
组件来渲染路由组件。当用户访问 /
路径时,Home
组件会被渲染到 router-view
组件中;当用户访问 /about
路径时,About
组件会被渲染到 router-view
组件中。
3. Vue Router 的路由配置和参数传递
3.1. 路由配置
在 Vue Router 中,我们可以使用 VueRouter
类来创建一个路由器实例,并使用 routes
属性来定义路由。每个路由都包含 path
和 component
两个属性,分别表示 URL 和对应的组件。例如,下面的例子中,我们定义了两个路由,分别对应 /
和 /about
路径:
import { createRouter, createWebHistory } from 'vue-router'
import Home from './components/Home.vue'
import About from './components/About.vue'const routers = [{ path: '/', component: Home },{ path: '/about', component: About }]const router = createRouter({history: createWebHistory(),routes,
})export default router;
3.2. 参数传递
在 Vue Router 中,我们可以通过 URL 来传递参数。URL 参数可以通过 props
和 query
两种方式传递。
3.2.1. props
使用 props
传递参数时,我们需要在路由配置中定义 props
函数,返回一个对象,对象的属性名对应组件中的 props
属性名,属性值对应 URL 参数名。例如,下面的例子中,我们定义了一个路由,传递了一个 id
参数:
const router = createRouter({history: createWebHistory(),routes: [{path: '/user/:id',component: User,props: route => ({ id: route.params.id })}]
})
3.2.2. query
使用 query
传递参数时,我们可以在 URL 中添加查询参数,例如 /?id=1
。在组件中,我们可以通过 $route.query
来获取查询参数。例如,下面的例子中,我们定义了一个路由,传递了一个 id
参数:
const router = createRouter({history: createWebHistory(),routes: [{path: '/user',component: User,props: route => ({ id: route.query.id })}]
})
3.3. 访问路由参数
注意:在 setup 形式下,不能使用this.$router
和this.$route
,作为替代,我们使用useRouter
和useRoute
函数:
<script setup lang="ts">
import { useRouter, useRoute } from 'vue-router'const router = useRouter()
const route = useRoute()console.log(router)
console.log(route)
</script>
4. Vue Router 的动态路由和嵌套路由
4.1. 动态路由
在Vue Router
中,我们可以使用动态路由来匹配不同的 URL。动态路由是指包含参数的路由,参数可以通过 :
来定义。例如,我们可以使用 /user/:id
来定义一个动态路由,其中 :id
表示参数。在组件中,我们可以通过 $route.params
来获取参数。例如,下面的例子中,我们定义了一个动态路由,根据不同的ID
渲染不同的用户信息:
const router = createRouter({history: createWebHistory(),routes: [{path: '/user/:id',component: User}]
})
在上面的例子中,我们定义了一个 /user/:id
的动态路由,并渲染 User
组件。在 User
组件中,我们可以通过 $route.params.id
来获取 ID
。
4.2. 嵌套路由
在 Vue Router 中,我们可以使用嵌套路由来组织复杂的页面结构。嵌套路由是指包含子路由的路由。例如,我们可以使用 /user
来定义一个父路由,然后在父路由中包含多个子路由。在组件中,我们可以使用 <router-view>
组件来渲染子路由对应的组件。例如,下面的例子中,我们定义了一个父路由 /user
,包含两个子路由 /user/profile
和 /user/posts
:
const router = createRouter({history: createWebHistory(),routes: [{path: '/user',component: User,children: [{path: 'profile',component: Profile},{path: 'posts',component: Posts}]}]
})
在上面的例子中,我们定义了一个 /user
的父路由,并渲染 User
组件。在 User
组件中,我们使用 <router-view>
组件来渲染子路由对应的组件。在父路由中,我们使用 children
属性来定义子路由。
5. 路由重定向
在某些情况下,我们可能需要将某个路由重定向到另一个路由,例如将 /a
重定向到 /b
。我们可以通过在路由配置中使用 redirect
来实现这一功能。
const router = new VueRouter({routes: [{ path: '/a', redirect: '/b' }]
})
我们还可以使用命名路由来实现重定向:
const router = new VueRouter({routes: [{ path: '/a', redirect: { name: 'foo' }}]
})
如果我们需要动态的重定向到一个路由,则可以在 redirect
中使用一个函数来实现:
const router = new VueRouter({routes: [{ path: '/a', redirect: to => {// 动态返回重定向目标return '/b'}}]
})
需要注意的是,如果我们使用了命名路由,那么在重定向时也需要使用命名路由。
6. Vue Router 的导航守卫和跳转控制
Vue Router 中的导航守卫可以用来控制路由的跳转,包括全局导航守卫、路由独享的导航守卫和组件内的导航守卫。
6.1. 全局导航守卫
全局导航守卫会在每次路由跳转时都被调用,包括 beforeEach
、beforeResolve
和 afterEach
三个方法。其中,beforeEach
方法用来进行路由跳转前的验证,可以通过 next
方法来进行跳转,例如:
6.1.1. 全局前置守卫(beforeEach)
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于等待中。
router.beforeEach((to, from) => {// ...// 返回 false 以取消导航return false
})
每个守卫方法接收两个参数:
to
: 即将要进入的目标from
: 当前导航正要离开的路由
可以返回的值如下:
false
: 取消当前的导航。如果浏览器的URL
改变了(可能是用户手动或者浏览器后退按钮),那么URL
地址会重置到from
路由对应的地址。一个路由地址
: 通过一个路由地址跳转到一个不同的地址,就像你调用router.push()
一样,你可以设置诸如replace: true
或name: 'home'
之类的配置。当前的导航被中断,然后进行一个新的导航,就和from
一样。
router.beforeEach(async (to, from) => {if (// 检查用户是否已登录!isAuthenticated &&// ❗️ 避免无限重定向to.name !== 'Login') {// 将用户重定向到登录页面return { name: 'Login' }}})
可选的第三个参数 next
:
进行路由跳转前的验证,并使用next
方法来进行跳转。
router.beforeEach((to, from, next) => {if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })else next()
})
6.1.2. 全局解析守卫(beforeResolve)
在导航被确认之前,和全局后置守卫(beforeEach)
相似,我们也可以注册一个全局解析守卫。这个守卫在全局前置守卫 (beforeEach)
、路由独享的前置守卫(beforeRouteEnter)
之后调用。
与全局前置守卫不同的是,它会在所有异步路由被解析之后调用,也就是在所有懒加载的组件被加载完之后。
const router = new VueRouter({ ... })router.beforeResolve((to, from, next) => {/* 在某些情况下,可能需要等待异步组件加载完成后才能执行后续操作 */next()
})
注意,该守卫不会像全局前置守卫一样,接收一个回调函数来调用 next
方法。相反,你只需要像 beforeEach
一样调用 next
方法,就可以被解析的异步组件所依赖的所有组件都被解析完毕。
6.1.3. 全局后置钩子(afterEach)
和全局前置守卫、全局解析守卫相似,我们也可以注册一个全局后置守卫。这个守卫在每个路由导航结束后被调用,即在所有的组件渲染完成之后,无论导航是成功的还是被中断的。
const router = new VueRouter({ ... })router.afterEach((to, from) => {/* 在这里执行一些操作 */
})
常用于页面分析、动态修改页面标题等。
需要注意的是,这里没有 next
方法,也无法改变导航本身。
6.2. 路由独享的导航守卫(beforeEnter)
除了全局前置守卫和全局解析守卫之外,我们还可以在路由配置上直接定义一个 beforeEnter
守卫。这个守卫只会对当前路由起作用。
const router = new VueRouter({routes: [{path: '/foo',component: Foo,beforeEnter: (to, from, next) => {// ...}}]
})
beforeEnter
的使用方式与全局前置守卫相同,接收三个参数 (to, from, next)
,并通过调用 next
方法来决定路由的行为。
需要注意的是,beforeEnter
不会像全局解析守卫一样等待异步组件加载完成后再调用,因此在使用异步组件时需要特别注意。
6.3. 组件内的导航守卫
在组件内部,我们也可以定义导航守卫。和全局导航守卫的使用方式相同,我们可以在组件配置中定义 beforeRouteEnter
、beforeRouteUpdate
和 beforeRouteLeave
三个导航守卫。这些守卫不同于全局导航守卫,它们可以访问组件实例 this
,因此可以对组件进行更细粒度的控制。
beforeRouteEnter
: 在路由进入前被调用。此时组件尚未被创建,因此无法访问组件实例this
,但可以通过传递一个回调函数来访问组件实例。beforeRouteUpdate
: 在路由更新时被调用(例如,使用相同组件的不同路由)。它可以访问组件实例this
,因此可以在路由更新时更改组件内部的状态。beforeRouteLeave
: 在路由离开当前组件时被调用。它可以访问组件实例this
,因此可以在路由离开前执行一些清理操作。
const Foo = {template: `...`,beforeRouteEnter (to, from, next) {// 在路由进入前被调用// 无法访问组件实例 `this`// 但可以通过传递一个回调来访问组件实例next(vm => {// 通过 `vm` 访问组件实例})},beforeRouteUpdate (to, from, next) {// 在路由更新时被调用// 可以访问组件实例 `this`},beforeRouteLeave (to, from, next) {// 在路由离开当前组件时被调用// 可以访问组件实例 `this`}
}
需要注意的是,这些导航守卫只对当前组件起作用,因此如果需要在多个组件中共享相同的导航守卫,仍然需要使用全局导航守卫。