入门
Vue Router 是 Vue 的官方客户端路由解决方案。
客户端路由由单页应用程序 (SPA) 使用,将浏览器 URL 绑定到用户看到的內容。当用户在应用程序中导航时,URL 会相应更新,但页面不需要从服务器重新加载。
Vue Router 基于 Vue 的组件系统构建。您配置 **路由** 以告知 Vue Router 为每个 URL 路径显示哪些组件。
先决条件
本指南假设您已经熟悉 Vue 本身。您不需要是 Vue 专家,但您可能偶尔需要参考 Vue 核心文档 以获取有关某些功能的更多信息。
一个例子
为了介绍一些主要思想,我们将考虑这个例子
让我们从查看根组件 App.vue
开始。
App.vue
<template>
<h1>Hello App!</h1>
<p>
<strong>Current route path:</strong> {{ $route.fullPath }}
</p>
<nav>
<RouterLink to="/">Go to Home</RouterLink>
<RouterLink to="/about">Go to About</RouterLink>
</nav>
<main>
<RouterView />
</main>
</template>
此模板使用 Vue Router 提供的两个组件,RouterLink
和 RouterView
。
我们使用自定义组件 RouterLink
来创建链接,而不是使用常规的 <a>
标签。这使 Vue Router 能够在不重新加载页面的情况下更改 URL,处理 URL 生成、编码以及其他各种功能。我们将在本指南的后面部分详细介绍 RouterLink
。
RouterView
组件告诉 Vue Router 在哪里渲染当前的 **路由组件**。这是与当前 URL 路径相对应的组件。它不必在 App.vue
中,您可以将其放在任何地方以适应您的布局,但它确实需要包含在某个地方,否则 Vue Router 不会渲染任何内容。
上面的示例还使用 {{ $route.fullPath }}
。您可以在组件模板中使用 $route
来访问表示当前路由的对象。
创建路由实例
路由实例是通过调用函数 createRouter()
创建的
import { createMemoryHistory, createRouter } from 'vue-router'
import HomeView from './HomeView.vue'
import AboutView from './AboutView.vue'
const routes = [
{ path: '/', component: HomeView },
{ path: '/about', component: AboutView },
]
const router = createRouter({
history: createMemoryHistory(),
routes,
})
routes
选项定义路由本身,将 URL 路径映射到组件。component
选项指定的组件是将在我们之前 App.vue
中的 <RouterView>
中渲染的组件。这些路由组件有时被称为视图,尽管它们只是普通的 Vue 组件。
路由支持各种其他选项,我们将在本指南的后面部分看到,但现在我们只需要 path
和 component
。
history
选项控制路由如何映射到 URL 以及反之亦然。对于 Playground 示例,我们使用 createMemoryHistory()
,它完全忽略浏览器 URL 并使用自己的内部 URL。这对于 Playground 来说效果很好,但它不太可能是您在真实应用程序中想要的。通常,您希望使用 createWebHistory()
,或者可能是 createWebHashHistory()
。我们将在本指南中更详细地介绍 历史模式 的主题。
注册路由插件
创建路由实例后,我们需要通过在应用程序上调用 use()
来将其注册为插件
createApp(App)
.use(router)
.mount('#app')
或者,等效地
const app = createApp(App)
app.use(router)
app.mount('#app')
与大多数 Vue 插件一样,对 use()
的调用需要在对 mount()
的调用之前进行。
如果您好奇这个插件的作用,它的一些职责包括
- 全局注册
RouterView
和RouterLink
组件。 - 添加全局
$router
和$route
属性。 - 启用
useRouter()
和useRoute()
组合式 API。 - 触发路由以解析初始路由。
访问路由和当前路由
您可能希望从应用程序的其他地方访问路由。
如果您从 ES 模块导出路由实例,则可以直接在需要的地方导入路由实例。在某些情况下,这是最佳方法,但如果我们在组件内部,我们还有其他选择。
在组件模板中,路由实例以 $router
的形式公开。这类似于我们之前看到的 $route
属性,但请注意末尾的额外 r
。
如果我们使用选项 API,我们可以在 JavaScript 代码中以 this.$router
和 this.$route
的形式访问这两个属性。Playground 示例中的 HomeView.vue
组件以这种方式访问路由
export default {
methods: {
goToAbout() {
this.$router.push('/about')
},
},
}
此方法调用 push()
,用于 编程导航。我们将在后面学习更多关于它的内容。
使用组合式 API,我们无法通过 this
访问组件实例,因此 Vue Router 包含一些组合式 API,我们可以使用它们。Playground 示例中的 AboutView.vue
使用了这种方法
<script setup>
import { computed } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const router = useRouter()
const route = useRoute()
const search = computed({
get() {
return route.query.search ?? ''
},
set(search) {
router.replace({ query: { search } })
}
})
</script>
现在不必理解所有这些代码。需要注意的关键是,组合式 API useRouter()
和 useRoute()
分别用于访问路由实例和当前路由。
下一步
如果您想查看使用 Vite 的完整示例,可以使用 create-vue 脚手架工具,它可以选择在示例项目中包含 Vue Router
npm create vue@latest
yarn create vue
pnpm create vue
create-vue 创建的示例项目使用了与我们在此处看到的类似的功能。您可能会发现它是一个有用的起点,可以用来探索本指南接下来的几页中介绍的功能。
本指南中的约定
单文件组件
Vue Router 最常用于使用捆绑器(例如 Vite)和 SFC(即 .vue
文件)构建的应用程序。本指南中的大多数示例都将以这种方式编写,但 Vue Router 本身并不需要您使用构建工具或 SFC。
例如,如果您使用的是 Vue 和 Vue Router 的全局构建,则这些库通过全局对象公开,而不是导入
const { createApp } = Vue
const { createRouter, createWebHistory } = VueRouter
组件 API 风格
Vue Router 可以与 Composition API 和 Options API 一起使用。在相关的情况下,本指南中的示例将展示以两种风格编写的组件。Composition API 示例通常会使用 <script setup>
,而不是显式的 setup
函数。
如果您需要关于这两种风格的复习,请参阅 Vue - API 风格。
router
和 route
在整个指南中,我们经常将路由器实例称为 router
。这是 createRouter()
返回的对象。您在应用程序中访问该对象的方式将取决于上下文。例如,在使用 Composition API 的组件中,可以通过调用 useRouter()
来访问它。使用 Options API,可以通过使用 this.$router
来访问它。
类似地,当前路由将被称为 route
。它可以通过使用 useRoute()
或 this.$route
在组件中访问,具体取决于组件使用的是哪个 API。
RouterView
和 RouterLink
组件 RouterView
和 RouterLink
都 全局注册,因此在组件模板中使用它们之前不需要导入它们。但是,如果您愿意,可以本地导入它们,例如 import { RouterLink } from 'vue-router'
。
在模板中,组件名称可以写成 PascalCase 或 kebab-case。Vue 的模板编译器支持两种格式,因此 <RouterView>
和 <router-view>
通常是等效的。您应该遵循项目中使用的任何约定。
如果您使用的是 DOM 内模板,那么 通常的注意事项 适用:组件名称必须写成 kebab-case,并且不支持自闭合标签。因此,您需要使用 <router-view></router-view>
而不是 <RouterView />
。