Vue 路由基础 - Vue Router Essentials
- 学一下 Vue Router 的一些 API
- Ref:https://router.vuejs.org/
创建路由
1 | import { createMemoryHistory, createRouter } from "vue-router"; |
这里用的是 createWebHistory,也可以使用
createWebHashHistory,或
createMemoryHistory,具体可以参考官方文档。
随后还需要将 router 挂载到 Vue 应用上:
1 | import { createApp } from "vue"; |
引入 RouterView 组件来渲染路由:
1 | <template> |
动态路由匹配
带参数的动态路由匹配
将给定匹配模式的路由映射到同一个组件,例如 RESTful 风格的路由:
1 | import User from "./User.vue"; |
路径参数 用冒号 : 表示。当一个路由被匹配时,它的
params 的值将在每个组件中以 route.params
的形式暴露出来
1 | <template> |
响应路由参数的变化
要对同一个组件中参数的变化做出响应的话,你可以简单地
watch $route 对象上的任意属性
1 | import { watch } from "vue"; |
捕获所有路由或 404 Not found 路由
1 | const routes = [ |
路由的匹配语法
在参数中自定义正则
1 | const routes = [ |
确保转义反斜杠 (
\),就像我们对\d(变成\\d)所做的那样,在 JavaScript 中实际传递字符串中的反斜杠字符。
可重复的参数
通过 *(0 个或多个)和 +(1
个或多个)将参数标记为可重复:
1 | const routes = [ |
也可以通过在右括号后添加它们与自定义正则结合使用
1 | const routes = [ |
Sensitive 与 strict 路由配置
默认情况下,所有路由是不区分大小写的,并且能匹配带有或不带有尾部斜线的路由。例如,路由
/users 将匹配
/users、/users/、甚至
/Users/。这种行为可以通过 strict 和
sensitive
选项来修改,它们既可以应用在整个全局路由上,又可以应用于当前路由上
1 | const router = createRouter({ |
可选参数
可以通过使用 ? 修饰符(0 个或 1
个)将一个参数标记为可选
1 | const routes = [ |
嵌套路由
一个被渲染的组件也可以包含自己嵌套的
<router-view>
1 | const routes = [ |
注意,以
/开头的嵌套路径将被视为根路径(如果加了的话,子路由path就不包含父路由的path)。这允许你利用组件嵌套,而不必使用嵌套的 URL。
此时,按照上面的配置,当你访问 /user/eduardo 时,在
User 的 router-view
里面什么都不会呈现,因为没有匹配到嵌套路由。也许你确实想在那里渲染一些东西。在这种情况下,你可以提供一个空的嵌套路径:
1 | const routes = [ |
嵌套的命名路由
1 | const routes = [ |
1 | const routes = [ |
这两种配置的区别在于,当我们采用基于 name
的路由跳转时,可以选择是否渲染子路由,如果使用父路由的 name
那么不会渲染子路由,反之则同时渲染父子路由,但需要注意的是,如果通过
path 或是跳转后刷新页面,则父子路由都将会被渲染。
忽略父组件
仅利用路由的父子关系,但不嵌套路由组件。这对于将具有公共路径前缀的路由分组在一起或使用更高级的功能时很有用,例如:路由独享的守卫或路由元信息。
1 | const routes = [ |
由于父级没有指定路由组件,顶级 <router-view>
将跳过父级并仅使用子路由组件。
命名路由
我们可以使用 name 而不是 path 来传递
to 属性给 <router-link>
1 | const routes = [ |
1 | <router-link :to="{ name: 'profile', params: { username: 'erina' } }"> |
编程式导航
导航到不同的位置
| 声明式 | 编程式 |
|---|---|
<router-link :to="..."> |
router.push(...) |
1 | import { useRouter } from "vue-router"; |
如果提供了 path,params 会被忽略,构建字符串路径或带有
path的对象时,请提供已编码的路径。使用encodeURIComponent编码每个动态片段
router.push 和所有其他导航方法都会返回一个
Promise,让我们可以等到导航完成后才知道是成功还是失败。
替换当前位置
| 声明式 | 编程式 |
|---|---|
<router-link :to="..." replace> |
router.replace(...) |
类似于 router.push,唯一不同的是,它在导航时不会向
history
添加新记录,正如它的名字所暗示的那样——它取代了当前的条目。
也可以直接在传递给 router.push 的 to
参数中增加一个属性 replace: true
1 | router.push({ path: "/home", replace: true }); |
横跨历史
该方法采用一个整数作为参数,表示在历史堆栈中前进或后退多少步,类似于
window.history.go(n)。
1 | // 向前移动一条记录,与 router.forward() 相同 |
命名视图
有时候想同时 (同级)
展示多个视图,而不是嵌套展示,例如创建一个布局,有 sidebar (侧导航) 和
main (主内容)
两个视图,这个时候命名视图就派上用场了。你可以在界面中拥有多个单独命名的视图,而不是只有一个单独的出口。如果
router-view 没有设置名字,那么默认为
default
1 | <router-view class="view left-sidebar" name="LeftSidebar" /> |
1 | const router = createRouter({ |
注意这里是
components而不是component,因为我们有多个视图需要渲染。
嵌套命名视图
1 | <div> |
1 | { |
其实就是在子路由中配置 components
重定向和别名
重定向
通过 routes 配置来完成
1 | const routes = [{ path: "/home", redirect: "/" }]; |
也可以是命名路由
1 | const routes = [{ path: "/home", redirect: { name: "homepage" } }]; |
甚至是一个方法,动态返回重定向目标
1 | const routes = [ |
请注意,导航守卫并没有应用在跳转路由上,而仅仅应用在其目标上。在上面的例子中,在
/home路由中添加beforeEnter守卫不会有任何效果。
在写 redirect 的时候,可以省略 component
配置,因为它从来没有被直接访问过,所以没有组件要渲染。唯一的例外是嵌套路由:如果一个路由记录有
children 和 redirect 属性,它也应该有
component 属性(这是因为子路由需要父路由的
router-view 组件承担。
相对重定向
1 | const routes = [ |
别名
alias 与 redirect 的区别在与是否改变 URL
1 | const routes = [{ path: "/", component: Homepage, alias: "/home" }]; |
这里访问 /home 也将渲染 Homepage 组件,同时
URL 不改变
也可以采用数组提供多个 alias
1 | const routes = [ |
路由组件传参
布尔模式
在你的组件中使用 $route 或 useRoute() 会与路由紧密耦合,这限制了组件的灵活性,我们也可以通过 props 配置来传递路由参数:
1 | <!-- User.vue --> |
同时需要配置 props: true,使 route.params
将被设置为组件的 props
1 | const routes = [{ path: "/user/:id", component: User, props: true }]; |
命名视图
对于具有命名视图的路由需要指定每一个视图的 props 配置
1 | const routes = [ |
对象模式
当 props 是一个对象时,它将被静态地传递给组件
1 | const routes = [ |
函数模式
可以创建一个返回 props 的函数
1 | const routes = [ |
通过 RouterView
以通过 <RouterView> 插槽 传递任意参数
1 | <RouterView v-slot="{ Component }"> |
本质上 RouterView 向 slot 暴露了需要渲染的
Component,因此我们可以使用<component>来渲染它,并传递任意参数。
活动链接
应用程序通常都会有一个渲染 RouterLink
列表的导航组件。我们也许想对这个列表中匹配当前路由的链接进行视觉区分。RouterLink
组件会为匹配当前路由的链接添加两个 CSS
类,router-link-active 和
router-link-exact-active。
链接在什么时候匹配当前路由
当满足以下条件时,RouterLink
被认为是匹配当前路由的:
- 它与当前路径匹配相同的路由记录(即配置的路由)。
- 它的
params与当前路径的params相同。
如果你使用了嵌套路由,任何指向祖先路由的链接也会被认为是匹配当前路由的,只要相关的
params 匹配。
其他路由属性,例如 query,不会被考虑在内。
路径不一定需要完全匹配。例如,使用 alias
仍然会被认为是匹配的,只要它解析到相同的路由记录和
params。
如果一个路由有
redirect,在检查链接是否匹配当前路由时不会跟随重定向。
精确匹配当前路由的链接
精确匹配不包括祖先路由。
1 | <RouterLink to="/user/erina"> |
考虑这两个链接,如果当前路径是
/user/erina/role/admin,那么这两个链接都会被认为是匹配当前路由的,因此
router-link-active
类会应用于这两个链接。但只有第二个链接会被认为是精确的,因此只有第二个链接会有
router-link-exact-active 类。
配置类名
RouterLink 组件有两个属性,activeClass 和
exactActiveClass,可以用来更改应用的类名:
1 | <RouterLink |
默认的类名也可以通过传递 linkActiveClass 和
linkExactActiveClass 选项给 createRouter()
来全局更改
1 | const router = createRouter({ |