router
基础
创建路由器实例
1 | const router = createRouter({ history: createMemoryHistory(), routes, }) |
注册路由器插件
一旦创建了我们的路由器实例,我们就需要将其注册为插件,这一步骤可以通过调用 use() 来完成。
1 | createApp(App) |
和大多数的 Vue 插件一样,use() 需要在 mount() 之前调用。
如果你好奇这个插件做了什么,它的职责包括:
- 全局注册
RouterView和RouterLink组件。 - 添加全局
$router和$route属性。 - 启用
useRouter()和useRoute()组合式函数。 - 触发路由器解析初始路由。
访问路由器和当前路由
选项式 API,我们可以在 JavaScript 中如下访问这两个属性:this.$router 和 this.$route。
组合式 API,我们不能通过 this 访问组件实例,所以 Vue Router 给我们提供了一些组合式函数。
1 | import { useRoute, useRouter } from 'vue-router' |
动态路由
在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数 :
1 | import User from './User.vue' |
你可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。例如:
params
| 匹配模式 | 匹配路径 | route.params |
|---|---|---|
| /users/:username | /users/eduardo | { username: 'eduardo' } |
| /users/:username/posts/:postId | /users/eduardo/posts/123 | { username: 'eduardo', postId: '123' } |
| route.query |
响应路由参数的变化
使用带有参数的路由时需要注意的是,当用户从 /users/johnny 导航到 /users/jolyne 时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。
1 | <script setup> |
捕获所有路由或 404 Not found 路由
常规参数只匹配 url 片段之间的字符,用 / 分隔。如果我们想匹配任意路径,我们可以使用自定义的 路径参数 正则表达式,在 路径参数 后面的括号中加入 正则表达式 :
1 | const routes = [ |
在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将pathMatch 参数标记为可选可重复。这样做是为了让我们在需要的时候,可以通过将 path 拆分成一个数组,直接导航到路由:
1 | router.push({ |
嵌套路由
一些应用程序的 UI 由多层嵌套的组件组成。在这种情况下,URL 的片段通常对应于特定的嵌套组件结构,例如:
1 | /user/johnny/profile /user/johnny/posts |
通过 Vue Router,你可以使用嵌套路由配置来表达这种关系。
这里的 <router-view> 是一个顶层的 router-view。它渲染顶层路由匹配的组件。同样地,一个被渲染的组件也可以包含自己嵌套的 <router-view>。例如,如果我们在 User 组件的模板内添加一个 <router-view>:
1 | <!-- User.vue --> |
要将组件渲染到这个嵌套的 router-view 中,我们需要在路由中配置 children:
1 | const routes = [ |
注意,以 / 开头的嵌套路径将被视为根路径。这允许你利用组件嵌套,而不必使用嵌套的 URL。
嵌套的命名路由
在处理命名路由时,你通常会给子路由命名:
1 | const routes = [ |
这将确保导航到 /user/:id 时始终显示嵌套路由。
在一些场景中,你可能希望导航到命名路由而不导航到嵌套路由。例如,你想导航 /user/:id 而不显示嵌套路由。那样的话,你还可以命名父路由,但请注意重新加载页面将始终显示嵌套的子路由,因为它被视为指向路径/users/:id 的导航,而不是命名路由:
1 | const routes = [ |
命名路由
使用 name 有很多优点:
- 没有硬编码的 URL。
params的自动编码/解码。- 防止你在 URL 中出现打字错误。
- 绕过路径排序,例如展示一个匹配相同路径但排序较低的路由。
所有路由的命名都必须是唯一的。如果为多条路由添加相同的命名,路由器只会保留最后那一条。
编程式导航
除了使用 <router-link> 创建 a 标签来定义导航链接,我们还可以借助 router 的实例方法,通过编写代码来实现。
导航到不同的位置
想要导航到不同的 URL,可以使用 router.push 方法。这个方法会向 history 栈添加一个新的记录,所以,当用户点击浏览器后退按钮时,会回到之前的 URL。
该方法的参数可以是一个字符串路径,或者一个描述地址的对象。例如:
1 | // 字符串路径 |
替换当前位置
它的作用类似于 router.push,唯一不同的是,它在导航时不会向 history 添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
replace
| 声明式 | 编程式 |
|---|---|
<router-link :to="..." replace> |
router.replace(...) |
也可以直接在传递给 router.push 的 to 参数中增加一个属性 replace: true : |
1 | router.push({ path: '/home', replace: true }) |
横跨历史
表示在历史堆栈中前进或后退多少步
1 | // 向前移动一条记录,与 router.forward() 相同 |
命名视图
有时候想同时 (同级) 展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和 main (主内容) 两个视图,这个时候命名视图就派上用场了。
1 | <!-- UserSettings.vue --> |
重定向
重定向也是通过 routes 配置来完成,下面例子是从 /home 重定向到 /:
1 | const routes = [{ path: '/home', redirect: '/' }] |
重定向的目标也可以是一个命名的路由:
1 | const routes = [{ path: '/home', redirect: { name: 'homepage' } }] |
相对重定向
也可以重定向到相对位置:
1 | const routes = [ |
别名
重定向是指当用户访问 /home 时,URL 会被 / 替换,然后匹配成 /。那么什么是别名呢?
将 / 别名为 /home,意味着当用户访问 /home 时,URL 仍然是 /home,但会被匹配为用户正在访问 /。
上面对应的路由配置为:
1 | const routes = [{ path: '/', component: Homepage, alias: '/home' }] |
通过别名,你可以自由地将 UI 结构映射到一个任意的 URL,而不受配置的嵌套结构的限制。使别名以 / 开头,以使嵌套路径中的路径成为绝对路径。你甚至可以将两者结合起来,用一个数组提供多个别名:
1 | const routes = [ |
不同的历史模式
Hash 模式
hash 模式是用 createWebHashHistory() 创建的。
它在内部传递的实际 URL 之前使用了一个井号(#)。由于这部分 URL 从未被发送到服务器,所以它不需要在服务器层面上进行任何特殊处理。不过,它在 SEO 中确实有不好的影响。如果你担心这个问题,可以使用 HTML5 模式。
Memory 模式
Memory 模式不会假定自己处于浏览器环境,因此不会与 URL 交互也不会自动触发初始导航。这使得它非常适合 Node 环境和 SSR。它是用 createMemoryHistory() 创建的,并且需要你在调用 app.use(router) 之后手动 push 到初始导航。
虽然不推荐,你仍可以在浏览器应用程序中使用此模式,但请注意它不会有历史记录,这意味着你无法_后退_或_前进_。
HTML5 模式
用 createWebHistory() 创建 HTML5 模式,推荐使用这个模式。