十四、使用 Vue Router 开发单页应用(2)
创始人
2024-03-17 00:52:31
0

本章概要

  • 动态路由匹配
    • 查询参数
  • 路由匹配语法
    • 参数的自定义正则表达式
    • 可重复参数
    • 可选参数
  • 嵌套路由

14.2 动态路由匹配

实际项目开发时,经常需要把匹配某种模式的路由映射到同一个组件。例如,有一个 Book 组件,对于所有 ID 各不相同的图书,都可以使用这个组件来渲染,这可以使用路径中的动态段(dynamic segment) 来实现。
继续《十四、使用 Vue Router 开发单页应用(1)》的项目,修改 App.vue ,使用 router-link 组件添加两个导航链接。代码如下:


在 components 目录下新建 Book.vue wen文件。如下:


接下来编辑 router 目录下的 index.js 文件,导入 Book 组件,并添加动态路径 /book/:id 的路由配置,如下:

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'export default createRouter({history: createWebHashHistory(),routes: [{path: '/',component: Home,},{path: '/news',component: News,},{path: '/books',component: Books,},{path: '/videos',component: Videos,},{path:'/book/:id',component:Book}]
})

在终端窗口执行 npm run serve 命令,运行项目,打开浏览器,出现 图书1和图书2链接,单击其中任意一个。结果如下:
在这里插入图片描述

在同一个路由中可以有多个参数,它们将映射到 route.params 中的相应字段,如下表所示:

模式匹配路径route.params
/user/:username/user/evan{username:‘evan’}
/user/:username/post/:post_id/user/evan/post/123{username:‘evan’,post_id:‘123’}

除了 route.params 外,route 对象还提供了其它有用信息,如 route.query (如果 URL 中有查询参数)、route.hash 等。

14.2.1 查询参数

URL 中带有查询参数的形式为 /book?id=1,这在传统的 Web 应用程序中很常见,根据查询参数想服务端请求数据。在单页应用程序开发中,也支持路径中的查询参数。

修改 App.vue 文件


修改 Book.vue


修改 index.js

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'export default createRouter({history: createWebHashHistory(),routes: [{path: '/',component: Home,},{path: '/news',component: News,},{path: '/books',component: Books,},{path: '/videos',component: Videos,},{path:'/book',component:Book}]
})

运行项目,单击“图书1”链接。查询参数演示结果如下:
在这里插入图片描述

14.3 路由匹配语法

大多数应用程序使用静态路由(如/news)和动态路由(如/book/1)就可以满足应用的需求,不过 Vue Router 也提供了更加强大的参数匹配能力。要匹配任何内容,可以使用自定义参数正则表达式,方法是在参数后面的圆括号中使用正则表达式。

14.3.1 参数的自定义正则表达式

当定义一个如 “:id”的参数时,Vue Router 在内部使用正则表达式“([^/]+)”(至少有一个不是斜杠 / 的字符)从 URL 中提取参数。
假设有两个路由 /:orderId 和 /:productName ,它们将匹配完全相同的 URL ,要想区分它们,最简单的方法是在路径中添加一个静态部分来区分。代码如下:

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

假设要限定 orderId 只能是数字,而 productName 可以是任何值,那么在参数 orderId 后的圆括号中使用正则表达式来说明。代码如下:

const routes = [// /:orderId 只能匹配数字{ path:'/o/:orderId(\\d+)' },// /:productName 匹配任何值{ path:'/p/:productName' }
]

14.3.2 可重复参数

可以使用修饰符“*”(零个或多个)、“+”(一个或多个)将参数标记为可重复的。如下:

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

这将给出一个 params 数组而不是字符串,并且在使用命名路由时也需要传递一个数组。如下:

// given { path:'/:chapters*',name:'chapters' },
router.resolve({ name:'chapters',params:{chapters: [] } }).href
// 结果:/
router.resolve({ name: 'chapters',params:{ chapters:['a','b'] }}).href
// 结果:/a/b
// given { path:'/:chapters+',name:'chapters' }
router.resolve({ name:'chapters',params:{ chapters:[] } }).href
// 因为 chapters 是空,这将抛出一个错误

还可以通过将 “*”和“+”添加到右括号后,与自定义正则表达式结合使用。

const router = [// 只匹配数字{ path:'/:chapters(\\d+)+' },{ path:'/:chapters(\\d+)*' }
]

14.3.3 可选参数

还可以使用“?”将参数标记为可选的。如下:

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

14.4 嵌套路由

在实际应用场景中,一个界面 UI 通常由多层嵌套的组件组合而成,URL 中的各段也按某种结构对应嵌套的各层组件。
在这里插入图片描述

路径 user/:id 映射到 User 组件,根据 ID 的不同,显示不同的用户信息。ID 为 1 的用户单击链接 user/1/profile ,将在用户1的视图中渲染 Profile 组件;单击 user/1/posts ,将在用户1的视图中渲染 Posts组件。

继续 14.2 节中的例子(将例子恢复为动态段),当单击“图书”链接时,以列表形式显示所有图书的书名,进一步单击单个书名链接,在 Books 视图中显示图书的详细信息。这可以通过嵌套路由来实现。
在 assets 目录下新建一个 books.js 文件,里面是图书数据。如下:

books.js

export default [{ id: 1, title: '标题1', desc: '描述1' },{ id: 2, title: '标题2', desc: '描述2' },{ id: 3, title: '标题3', desc: '描述3' },
]

这里硬编码了图书数据,只是为了演示需要,真实场景中,图书数据应该是通过 Ajax 请求从服务端加载得到。
修改 Books.vue,以列表方式显示图书数据,添加导航链接,并使用 router-view 指定 Book 组件渲染的位置。如下:

Books.vue


注意删除 App.vue 中的图书1 和图书2 的 router-link 的配置。
修改 router 目录下的 index.js 文件,增加嵌套路由的配置。如下:

import { createRouter, createWebHashHistory } from 'vue-router'
import Home from '@/components/Home'
import News from '@/components/News'
import Books from '@/components/Books'
import Videos from '@/components/Videos'
import Book from '@/components/Book'export default createRouter({history: createWebHashHistory(),routes: [{path: '/',component: Home,},{path: '/news',component: News,},{path: '/books',component: Books,children: [{ path: '/book/:id', component: Book }]},{path: '/videos',component: Videos,},]
})

说明:

  • 要在嵌套的出口(即 Books 组件中的 router-view)中渲染组件,需要在 routes 选项的配置中使用 children 选项。children 选项只是路由配置对象的另一个数组,如同 routes 本身一样,因此,可以根据需要继续嵌套路由。
  • 以“/”开头的嵌套路径被视为根路径。如果导航链接设置的是 /books/book/id 这种形式,那么这里配置路径时,需要去掉“/”,即 {path:‘book/:id’,component:Book}

Book.vue


在终端窗口中运行项目,打开浏览器,单击“图书”链接后,任选一本图书,结果如下:
在这里插入图片描述

在实际场景中,当单击某本图书链接时,应该向服务器发起 Ajax 请求来获取图书详细数据,于是想到在 Book 组件中通过生命周期钩子函数来实现,然而,这行不通。

因为当两个路由都渲染同一个组件时,如从 book/1 导航到 book/2 时,Vue 会复用先前的 Book 实例,比起销毁旧实例再创建新实例,复用会更加高效。但是这就意味着组件间的生命周期钩子不会再被调用,所以也就无法在生命周期构钩子中去根据路由参数的变化更新数据。

要对同一组件的路由参数更改做出响应,只需监听 route.params 即可。
修改 Book.vue ,当路由参数变化时,更新图书详细数据。如下:

Book.vue


说明
(1)只有路由参数发生变化时,route.params 的监听才会被调用,这意味着第一次渲染 Book 组件时,通过 route.params 的监听器是得不到数据的,因此在 created 钩子中先获取第一次渲染时的数据。当然,也可以向 watch 方法传入一个选项对象作为第3个参数,设置 immediate 选项参数为 true ,使监听器回调函数在监听开始后立即执行,即不需要在 created 钩子中先获取一次数据。如下:

created(){// this.book = Books.find((item) => item.id == this.$route.params.id);this.$watch(() => this.$route.params,(toParams) => {this.book = Books.find((item) => item.id == toParams.id);})
}

(2)route.params 监听器回调函数的 toParams 参数表示即将进入的目标路由的参数,该函数还可以带一个 previousParams 参数,表示当前导航正要离开的路由的参数。

运行项目,单击不同的图书链接将显示对应图书的详细信息,如图:
在这里插入图片描述

除了监听 route 对象外,还可以利用 Vue Router 中的导航守卫(navigation guard):beforeRouteUpdate,可以把它理解为是针对路由的一个钩子函数。
修改 Book.vue 删除 route.params 监听器,改用 beforeRouteUpdate 来实现。如下:


beforeRouteUpdate 在当前路由改变,但是该组价被复用时调用,它有两个常用的参数。to 表示即将进入的目标路由位置对象;from 表示当前导航正要离开的路由位置对象。此处只用到了参数 to。

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...