多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Vue Router 重定向与别名实战指南:redirect 与 alias 的配置、原理与源码解析

Vue Router 重定向与别名实战指南:redirect 与 alias 的配置、原理与源码解析 Vue Router 重定向与别名实战指南redirect 与 alias 的配置、原理与源码解析【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router重定向Redirect与别名Alias是 Vue Router 中两个最容易混淆却又极其常用的路由配置能力重定向会把用户访问的 URL 改写为另一个地址再匹配路由而别名则让同一个组件在不改变 URL 的前提下被多个地址匹配到。本文以 Vue 2 官方路由库 vue-router 的日本语官方文档 redirect-and-alias.md 为主线完整覆盖 redirect 的三种配置形式与 alias 的全部写法并结合仓库内 create-matcher.js、create-route-map.js 等核心源码与真实示例、端到端测试讲透二者背后的匹配原理与实战陷阱。读完本文你将能在routes配置中自如地实现路径迁移、动态跳转、多 URL 复用同一组件等常见需求。一、重定向Redirect在路由配置中完成的跳转重定向是直接在routes配置中声明的不需要编写任何额外的跳转逻辑。以/a重定向到/b为例const router new VueRouter({ routes: [{ path: /a, redirect: /b }] })当用户访问/a时Vue Router 会将该 URL 替换为/b然后按/b完成路由匹配与渲染地址栏最终显示为/b。从类型定义看redirect属于RouteConfig的可选属性见 types/router.d.ts 中的_RouteConfigBase它支持三种取值形式字符串路径、带name的命名路由对象、以及返回路径或 location 对象的函数下面逐一展开。1.1 字符串路径重定向最直接的形式目标路径可以是绝对路径也可以是相对路径详见下文“高级用法”。1.2 命名路由重定向当目标路由已通过name命名时可以重定向到命名路由避免硬编码路径const router new VueRouter({ routes: [{ path: /a, redirect: { name: foo } }] })重定向对象还支持query、hash、params字段。从 src/create-matcher.js 中redirect函数的实现可以看到重定向时会对字段做“覆盖式合并”如果重定向对象显式声明了query、hash或params则使用声明的值否则沿用原始访问地址location中携带的值const { name, path } re let { query, hash, params } location query re.hasOwnProperty(query) ? re.query : query hash re.hasOwnProperty(hash) ? re.hash : hash params re.hasOwnProperty(params) ? re.params : params也就是说/a?foobar重定向到/b后query 默认会保留为?foobar只有显式声明query: null等才会丢弃。仓库示例 examples/redirect/app.js 中就有利用这一行为实现的动态重定向{ path: /dynamic-redirect/:id?, redirect: to { const { hash, params, query } to if (query.to foo) { return { path: /foo, query: null } } if (hash #baz) { return { name: baz, hash: } } if (params.id) { return /with-params/:id } else { return /bar } } }1.3 函数式动态重定向redirect还可以是一个函数它接收“目标路由”即用户即将访问的 route 对象作为参数并返回一个重定向目标字符串路径或 location 对象const router new VueRouter({ routes: [ { path: /a, redirect: to { // to 即目标路由可读取 hash / params / query 等字段 // 返回重定向的 path 或 location 对象 } } ] })函数式重定向最常见的用途是根据访问者携带的参数路径参数、query、hash决定不同的跳转目的地实现 A/B 分流、多语言跳转、旧路由兼容等场景。1.4 重定向与导航守卫的关系重要官方文档特别强调导航守卫Navigation Guards不会作用于“发起重定向的路由”而只会作用于重定向的“目标路由”。例如给/a路由添加beforeEnter守卫是无效的因为/a只是中转站真正进入的是/b的守卫。相关说明可参见导航守卫日文版见 navigation-guards.md。这一点在源码层面也有印证重定向发生在createMatcher.match返回路由之前——当匹配到的记录存在record.redirect时_createRoute会直接进入redirect()分支src/create-matcher.js此时守卫还没有机会执行而是进入对目标路由的重新匹配流程function _createRoute (record, location, redirectedFrom) { if (record record.redirect) { return redirect(record, redirectedFrom || location) } if (record record.matchAs) { return alias(record, location, record.matchAs) } return createRoute(record, location, redirectedFrom, router) }另外被重定向的原始地址会记录在最终路由的redirectedFrom字段中见 src/util/route.js 中createRoute的实现this.$route.redirectedFrom在组件中可以直接读取。对应地导航失败枚举中也保留了NavigationFailureType.redirected见 types/router.d.ts说明重定向是导航流程中被显式建模的一类结果。1.5 重定向的高级用法来自官方示例仓库的 examples/redirect/app.js 展示了官方文档提到的“更高级用法”完整罗列了以下场景可直接复制运行配合 examples/server.js 与history模式用法配置示例行为相对路径重定向{ path: relative-redirect, redirect: foo }位于/的子路由中跳转到同级兄弟路由/fooquery 保留绝对路径重定向{ path: /absolute-redirect, redirect: /bar }跳转到绝对路径/bar命名路由重定向{ path: /named-redirect, redirect: { name: baz } }按名称解析目标路由带参数重定向{ path: /redirect-with-params/:id, redirect: /with-params/:id }参数被透传到目标路由对应示例中的fillParams逻辑兜底重定向{ path: *, redirect: / }任意未匹配路径都跳回首页通配路由始终排最后匹配见 create-route-map.js其中“相对路径重定向”在源码中由resolveRecordPath处理重定向路径会基于当前记录的父级路径进行解析src/create-matcher.jsconst rawPath resolveRecordPath(path, record) const resolvedPath fillParams(rawPath, params, redirect route with path ${rawPath})而参数填充由 src/util/params.js 的fillParams完成它利用path-to-regexp的编译缓存将/with-params/:id与{ id: 123 }组合成/with-params/123。二、别名AliasURL 不变按另一条路由渲染2.1 别名与重定向的本质区别先看官方文档给出的精确定义重定向意味着用户访问/a时URL 会被替换为/b然后按/b匹配/a的别名为/b意味着用户访问/b时URL 保持/b不变但匹配结果等同于访问了/a。一句话概括重定向改变地址栏 URL别名不改变 URL 只改变匹配结果。2.2 别名的基本配置const router new VueRouter({ routes: [{ path: /a, component: A, alias: /b }] })配置后访问/b会渲染组件A但地址栏仍是/b且$route.path也是/b更准确地说$route是基于别名路径构造的组件接收的params来自别名匹配结果。从 types/router.d.ts 可以看到alias的类型是string | string[]即支持多个别名。官方文档还强调了一个关键优势别名让你可以把任意 URL 映射到某个 UI 结构而不受路由配置嵌套结构的约束。例如你在深层嵌套的路由下写了一个path: foo正常访问它需要/parent/foo但通过alias: /foo就能让/foo直接命中该组件——这正是“解耦 URL 与组件层级”的价值。2.3 别名的源码实现别名的底层实现分布在两个文件中注册阶段src/create-route-map.js 的addRouteRecord中alias会被统一归一化为数组存入record.aliasalias: route.alias ? typeof route.alias string ? [route.alias] : route.alias : []随后对每个别名递归调用addRouteRecord并传入matchAs即被别名指向的原始记录路径开发环境下如果发现别名与路径相同还会给出警告并跳过该别名if (process.env.NODE_ENV ! production alias path) { warn(false, Found an alias with the same value as the path: ${path}. You have to remove that alias. It will be ignored in development.) continue } const aliasRoute { path: alias, children: route.children } addRouteRecord(pathList, pathMap, nameMap, aliasRoute, parent, record.path || /)注意别名记录会继承原路由的children这是嵌套别名能够工作的原因。匹配阶段src/create-matcher.js 中当匹配到的记录带有matchAs时走alias()分支用fillParams将别名路径与参数组合成目标路径再重新match一次取匹配链最末端的记录作为最终渲染记录并把别名匹配得到的params写回function alias (record, location, matchAs) { const aliasedPath fillParams(matchAs, location.params, aliased route with path ${matchAs}) const aliasedMatch match({ _normalized: true, path: aliasedPath }) if (aliasedMatch) { const matched aliasedMatch.matched const aliasedRecord matched[matched.length - 1] location.params aliasedMatch.params return _createRoute(aliasedRecord, location) } return _createRoute(null, location) }2.4 别名的全部形态来自官方示例仓库的 examples/route-alias/app.js 是文档指明的进阶示例覆盖了别名在真实项目中的所有形态routes: [ // 顶层路由别名绝对路径 { path: /root, component: Root, alias: /root-alias }, { path: /home, component: Home, children: [ // 绝对路径别名/foo 直接命中 /home/foo { path: foo, component: Foo, alias: /foo }, // 相对路径别名等价于 /home/bar-alias 命中 /home/bar { path: bar, component: Bar, alias: bar-alias }, // 多别名同时命中 /baz 与 /home/baz-alias { path: baz, component: Baz, alias: [/baz, baz-alias] }, // 空字符串别名/home 命中默认子路由 /home/default { path: default, component: Default, alias: }, // 嵌套别名/home/nested-alias/foo 命中 /home/nested/foo { path: nested, component: Nested, alias: nested-alias, children: [ { path: foo, component: NestedFoo } ] } ] } ]对照端到端测试 test/e2e/specs/route-alias.js 可以逐条验证预期行为例如访问/root-aliasURL 保持/root-alias渲染root组件访问/fooURL 保持/foo渲染 Home 布局中的foo组件访问/home/bar-aliasURL 不变渲染bar组件访问/baz与/home/baz-alias都渲染baz组件访问/home/nested-alias/fooURL 不变渲染nested foo组件。这说明别名在嵌套路由、默认子路由、多别名等复杂结构下均能保持“URL 原样、匹配生效”的核心语义。三、重定向与别名何时用哪个维度重定向redirect别名alias地址栏 URL会被替换为目标地址保持不变匹配对象重定向后按目标路由重新匹配直接命中被别名的原路由典型场景路由迁移、旧链接兼容、动态跳转、权限分流、404 兜底同一组件暴露多个 URL、解耦 URL 与嵌套层级、SEO 友好地址参数/query 处理默认继承原地址的 query/hash/params可显式覆盖别名路径参与参数填充$route按别名构造守卫执行守卫只作用于目标路由与普通路由一致作用于最终命中的记录选择建议如果希望用户看到规范的新地址例如永久迁移用redirect如果只是希望多个地址都能渲染同一组件、且地址栏保持用户输入不变用alias。四、注意事项与常见陷阱别名与路径相同会告警开发模式下若alias path会在控制台输出警告并跳过该别名见 create-route-map.js 中的addRouteRecord。通配路由始终最后匹配createRouteMap会强制把*路由挪到pathList末尾create-route-map.js因此{ path: *, redirect: / }这样的兜底重定向不会抢占其他路由。顶层路由必须以/开头开发模式下非嵌套路由缺少前导斜杠会输出警告别名中的相对路径则依赖父级路径解析。重定向守卫陷阱不要在“被重定向的源路由”上寄望守卫生效需要拦截应写在目标路由上全局守卫与redirectedFrom可用于追踪重定向来源。动态添加路由也支持别名matcher.addRoute在添加带别名的父路由时会同步为其别名注册子路由见 src/create-matcher.js 的addRoute实现。五、测试与验证仓库为这两个特性提供了完整的自动化验证可作为理解行为边界的参考端到端测试 test/e2e/specs/redirect.js逐一断言 12 种重定向链接的跳转结果覆盖相对/绝对/动态/命名/带参/兜底重定向并验证“直接输入 URL 访问时的初始重定向”行为端到端测试 test/e2e/specs/route-alias.js断言 7 种别名访问的 URL 保持不变且渲染正确的组件单元测试 test/unit/specs/create-matcher.spec.js验证addRoute注册别名后getRoutes()的数量变化{ path: /c, alias: [/a, /d] }会多出两条别名记录从数据结构层面印证别名会被展开为独立的路由记录。小结重定向与别名是 Vue Routerroutes配置中相辅相成的两个能力redirect支持字符串、命名路由对象与函数三种形式本质是“改写 URL 后重新匹配”常用于迁移与动态跳转alias支持字符串与数组本质是“URL 不变、换路由渲染”常用于解耦 URL 与组件层级。结合本仓库的 create-matcher.js、create-route-map.js 源码以及 examples/redirect/app.js、examples/route-alias/app.js 两个可直接运行的官方示例你可以在实际项目中准确选用二者并规避守卫失效、路径冲突等典型陷阱。【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表