主页 > 互联网  > 

Vue学习记录21

Vue学习记录21
Vue Router

Vue Router 是 Vue.js 的官方路由。它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用变得轻而易举。功能包括:

嵌套路由映射动态路由选择模块化、基于组件的路由选择路由参数、查询、通配符展示由Vue.js 的过渡系统提供的过渡效果细致的导航控制自动激活 CSS 类的链接HTML5 history 模式或 hash 模式可定制的滚动行为URL的正确编码

安装

 包管理器

对于一个现有的使用 JavaScript 包管理器的项目,你可以从 npm registry  中安装 Vue Router:

npm install vue-router@4

如果你打算启动一个新项目,你可能会发现使用 create-vue  这个脚手架工具更容易,他能创建一个基于Vite的项目,并包含加入 Vue Router 的选项:

npm create vue@latest

你需要回答一些关于你想创建的项目类型的问题。如果您选择安装 Vue Router,示例应用还将演示Vue Router 的一些核心特性。

使用包管理器的项目通常会使用ES模块来访问 Vue Router,例如 import { createRouter }  from  ‘vue-router'。

直接下载/CDN

unpkg /vue-router@4

Unpkg  提供了基于 npm 的 CDN 链接。上述链接将始终指向 npm 上的最新版本。 也可以通过像  unpkg /vue-router@4.0.15/dist/vue-router.global.js 这样的 URL 来使用特定的版本或 Tag。

这将把 Vue Router 暴露在一个全局的 VueRouter 对象上,例如 VueRouter.createRouter(...)。

使用

Vue Router 是 Vue 官方的客户端路由解决方案。

客户端路由的作用是在单页应用(SPA)将浏览器的URL和用户看到的内容绑定起来。当用户在应用中浏览不同页面时,URL 会随之更新,但页面不需要从服务器重新加载。

Vue Router 基于Vue 的组件系统构建,你可以通过配置路由来告诉 Vue Router 为每个 URL 路径显示哪些组件。

示例

为了引入一些核心概念,将使用如下的示例:

先来看看根组件,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>

在这个 template 中使用了两个由 Vue Router 提供的组件:RouterLink 和 RouterView。

不同于常规的 <a> 标签,我们使用组件 RouterLink 来创建链接。这使得 Vue Router 能够在不重新加载页面的情况下改变URL,处理URL的生成、编码和其他功能。

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 组件。

这里的 history 选项控制了路由和 URL 路径是如何双向映射的。这里使用了 createMemoryHistory(),它会完全忽略浏览器的 URL er使用自己内部的 URL。通常,你应该使用 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() 组合式函数。触发路由器解析初始路由。

访问路由器和当前路由

你很可能想要在应用的其他地方访问路由器。

如果你是从 ES 模块导出路由实例的,你可以将路由器实例直接导入你需要它的地方。 在一些情况下这是最好的方法,但如果我们在组件内部,那么我们还有其他选择。

在组件模板中,路由器实例将被暴露为 $router。这与同样被暴露的 $route 一样,但注意前者最后有一个额外的 r。

如果我们使用选项式API,我们可以在JavaScript中访问这两个属性:this.$router 和 this.$route。

export default { methods: { goToAbout() { this.$router.push('/about') }, }, }

这里调用了 push(),这是用于编程式导航的方法。

对于组合式API,我们不能通过 this 访问组件实例,所以 Vue Router 给我们提供了一些组合式函数。

<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>

这里的关键是要知道可以通过 useRouter() 和 useRoute() 来访问路由器实例和当前路由。

单文件组件

Vue Router 经常在配合打包工具 (如 Vite)和单文件组件(即.vue文件)的应用中使用。但是 Vue Router 本身并不要求你使用构建工具或单文件组件。

router和route

router常常作为路由器实例提及。即由 createRouter() 返回的对象。 在应用中,访问该对象的方式取决于上下文。例如,在组合式API中,它可以通过调用 useRouter() 来访问。 在选项式API中,它可以通过 this.$router 来访问。

类似地,当前路由会以 route 被提及。基于不同 API 风格的组件,它可以通过 useRoute() 或 this.$route 来访问。

RouterView 和 RouterLink

组件 RouterView 和 RouterLink 都是全局注册的,因此它们不需要在组件模板中导入。但你也可以通过局部导入它们,例如 import { RouterLink } from 'vue-router'。

在模板中,组件的名字可以式 PascalCase 风格或 kebab-case 风格的。 Vue的模板编译器支持两种格式,因此 <RouterView> 和 <router-view> 通常是等效的。此时应该遵循你自己项目中使用的约定。

如果使用 DOM 内模板,那么需要注意:组件名字必须使用 kebab-case 风格且不支持自闭合标签。因此你不能直接写<RouterView>,而需要使用<router-view></router-view>。

带参数的动态路由匹配

很多时候,我们需要将给定匹配模式的路由映射到同一个组件。例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但用户ID不同。 在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数:

import User from './User.vue' // 这些都会传递给 `createRouter` const routes = [ // 动态字段以冒号开始 { path: '/users/:id', component: User }, ]

现在像 /user/johnny 和 /users/jolyne 这样的 URL 都会映射到同一个路由。

路径参数用冒号 : 表示。当一个路由被匹配时,它的 params 的值将在每个组件中以 route.params 的形式暴露出来。因此,我们可以通过更新 User 的模板来呈现当前的用户 ID:

<template> <div> <!-- 当前路由可以通过 $route 在模板中访问 --> User {{ $route.params.id }} </div> </template>

你可以在同一个路由中设置有多个 路径参数,它们会映射到 $route.params 上的相应字段。例如:

匹配模式匹配路径route.params/users/:username/users/eduardo{ username: 'eduardo' }/users/:username/posts/:postId/users/eduardo/posts/123{ username: 'eduardo', postId: '123' }

除了 route.params 之外,route 对象还公开了其他有用的信息,如 route.query (如果 URL中存在参数)、route.hash等。

 

响应路由参数的变化

使用带有参数的路由时需要注意的是,当用户从 /users/johny 导航到 /users/jolyne 时,相同的组件实例将被重复使用。因为两个路由都渲染同个组件,比起销毁再创建,复用则显得更加高效。不过,这也意味着组件的生命周期钩子不会被调用。

要对同一个组件中参数的变化做出响应的话,你可以简单地 watch $route 对象上地任意属性,在这个场景中,就是 $route.params:

<script setup> import { watch } from 'vue' import { useRoute } from 'vue-router' const route = useRoute() watch(() => route.params.id, (newId, oldId) => { // 对路由变化做出响应... }) </script>

或者,使用 beforeRouteUpdate 导航守卫,它还允许你取消导航:

<script setup> import { onBeforeRouteUpdate } from 'vue-router' // ... onBeforeRouteUpdate(async (to, from) => { // 对路由变化做出响应... userData.value = await fetchUser(to.params.id) }) </script>

捕获所有路由或 404 Not found 路由

常规参数只匹配 url 片段之间的字符,用 / 分隔。如果我们想匹配任意路径,我们可以使用自定义的路径参数正则表达式,在路径参数后面的括号中加入正则表达式:

const routes = [ // 将匹配所有内容并将其放在 `route.params.pathMatch` 下 { path: '/:pathMatch(.*)*', name: 'NotFound', component: NotFound }, // 将匹配以 `/user-` 开头的所有内容,并将其放在 `route.params.afterUser` 下 { path: '/user-:afterUser(.*)', component: UserGeneric }, ]

在这个特定的场景中,我们在括号之间使用了自定义正则表达式,并将 pathMatch 参数标记为可选可重复。这样做是为了让我们在需要的时候,可以通过将 path 拆分成一个数组,直接导航到路由:

router.push({ name: 'NotFound', // 保留当前路径并删除第一个字符,以避免目标 URL 以 `//` 开头。 params: { pathMatch: this.$route.path.substring(1).split('/') }, // 保留现有的查询和 hash 值,如果有的话 query: route.query, hash: route.hash, })

路由的匹配语法

大多数应用都会使用 /about 这样的静态路由和 /user/:userId 这样的动态路由,但是Vue Router 可以提供更多的方式!

Tip

为了简单起见,所有的路由都省略了 component 属性,只关注 path 值。

在参数中自定义正则 

当定义像 :userId 这样的参数时,我们内部使用以下的正则 ([^/]+) (至少一个不是斜杠 / 的字符)来从 URL 中提取参数。 这很好用,除非你需要根据参数的内容来区分两个路由。 想想一下,两个路由 /:orderId 和 /:productName, 两者会匹配完全相同的 URL,所以我们需要一种方法来区分它们。最简单的方法就是在路径中添加一个静态部分来区分它们:

const routes = [ // 匹配 /o/3549 { path: '/o/:orderId' }, // 匹配 /p/books { path: '/p/:productName' }, ]

但在某些情况下,我们并不想添加静态的 /o/p 部分。 由于,orderId 总是一个数字,而 productName 可以是任何东西,所以我们可以在括号中为参数指定一个自定义的正则:

const routes = [ // /:orderId -> 仅匹配数字 { path: '/:orderId(\\d+)' }, // /:productName -> 匹配其他任何内容 { path: '/:productName' }, ]

现在,转到 /25 将匹配 /:orderId ,其他情况将会匹配 /:productname。routes 数组的顺序并不重要!

Tip

确保转义反斜杠(\),就像我们对 \d (变成 \\d)所做的那样,在 JavaScript 中实际传递字符串中的反斜杠字符。

可重复的参数 

如果你需要匹配具有多个部分的路由,如 /first/second/third,你应该 *(0个或多个)和 + (1个或多个)将参数标记为可重复:

const routes = [ // /:chapters -> 匹配 /one, /one/two, /one/two/three, 等 { path: '/:chapters+' }, // /:chapters -> 匹配 /, /one, /one/two, /one/two/three, 等 { path: '/:chapters*' }, ]

这将为你提供一个参数数组,而不是一个字符串,并且在使用命名路由时也需要你传递一个数组:

// 给定 { path: '/:chapters*', name: 'chapters' }, router.resolve({ name: 'chapters', params: { chapters: [] } }).href // 产生 / router.resolve({ name: 'chapters', params: { chapters: ['a', 'b'] } }).href // 产生 /a/b // 给定 { path: '/:chapters+', name: 'chapters' }, router.resolve({ name: 'chapters', params: { chapters: [] } }).href // 抛出错误,因为 `chapters` 为空

这些也可以通过在右括号后添加它们与自定义正则结合使用:

const routes = [ // 仅匹配数字 // 匹配 /1, /1/2, 等 { path: '/:chapters(\\d+)+' }, // 匹配 /, /1, /1/2, 等 { path: '/:chapters(\\d+)*' }, ]

Sensitive 与 strict 路由配置

默认情况下,所有路由是不区分大小写的,并且能匹配带有或不带有尾部斜线的路由。例如,路由 /users 将匹配 /users、/users/、甚至 /Users/。这种行为可以通过 strict 和 sensitive 选项来修改,它们既可以应用在整个全局路由上,又可以应用于当前路由上:

const router = createRouter({ history: createWebHistory(), routes: [ // 将匹配 /users/posva 而非: // - /users/posva/ 当 strict: true // - /Users/posva 当 sensitive: true { path: '/users/:id', sensitive: true }, // 将匹配 /users, /Users, 以及 /users/42 而非 /users/ 或 /users/42/ { path: '/users/:id?' }, ], strict: true, // applies to all routes })

可选参数

你也可以通过使用 ? 修饰符(0个或1个)将一个参数标记为可选:

const routes = [ // 匹配 /users 和 /users/posva { path: '/users/:userId?' }, // 匹配 /users 和 /users/42 { path: '/users/:userId(\\d+)?' }, ]

请注意,*在技术上也标志着一个参数是可选的,但 ?参数不能重复。

调试

如果你需要探究你的路由是如何转化为正则的,以了解为什么一个路由没有被匹配,或者,报告一个bug,你可以使用路径排名工具。它支持通过URL分享你的路由。

标签:

Vue学习记录21由讯客互联互联网栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Vue学习记录21