拓冰建站拓冰建站
首页 / 资讯中心 / 正文

vue-router 编程式导航完全指南:router.push / replace / go 的原理与实战

vue-router 编程式导航完全指南router.push / replace / go 的原理与实战【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router导读本指南聚焦 Vue 2 官方路由库 vue-router 的编程式导航能力除使用router-link进行声明式导航外你还可以通过$router实例方法push、replace、go在 JavaScript 代码中精确控制路由跳转。读完本文你将掌握三类导航方法的完整签名、参数形态与回调约定理解 path/name/query/params 的解析规则并能依据源码看懂push、replace、go在history、hash、abstract三种模式下的底层实现差异。本文以仓库中的 docs-gitbook/es/essentials/navigation.md及对应英文版 docs/guide/essentials/navigation.md为主线结合 src/router.js、src/history 等源码展开。声明式导航与编程式导航的对照除了用router-link渲染a标签完成声明式导航vue-router 还允许通过路由器实例的方法在代码中完成同样的跳转。二者的对照关系如下声明式Declarative编程式Programmaticrouter-link :to...router.push(...)router-link :to... replacerouter.replace(...)其中编程式指的是在组件的方法、事件回调、异步流程等任意 JavaScript 上下文中主动触发导航而非依赖用户点击链接。在 Vue 组件中访问路由器实例在 Vue 实例内部你可以通过$router访问路由器实例因此可以直接调用this.$router.push。这一点由插件安装逻辑保证调用Vue.use(VueRouter)后src/install.js 会在根组件上注入$router与$route所有后代组件均可访问参见示例 examples/basic/app.js 中对this.$router.push的使用。在非组件环境中如独立的 JS 模块则直接使用创建好的router实例调用这些方法。router.push(location, onComplete?, onAbort?)router.push用于导航到一个不同的 URL。它会向历史记录栈推入一条新记录因此当用户点击浏览器后退按钮时会被带回上一个 URL——这正是它与替换式导航的本质区别。router-link内部正是在点击时调用router.push在 src/components/link.js 的渲染逻辑中点击处理函数handler会先通过guardEvent过滤掉带修饰键如 Ctrl/Cmd、右键、target_blank等不应拦截的情况然后执行router.push(location, noop)除非设置了replace属性此时改为router.replace(location, noop)。也就是说router-link :to...等价于执行router.push(...)。location 参数字符串与描述对象push的第一个参数location可以是字符串路径也可以是一个位置描述对象RawLocation。官方示例// 字面量字符串路径 router.push(home) // 对象 router.push({ path: home }) // 命名路由 router.push({ name: user, params: { userId: 123 }}) // 带 query结果得到 /register?planprivate router.push({ path: register, query: { plan: private }})关键规则path 存在时 params 被忽略英文版文档docs/guide/essentials/navigation.md进一步补充了一条极易踩坑的规则如果提供了pathparams会被忽略query不会如上例所示。要传参要么使用命名路由要么把参数拼进path字符串const userId 123 router.push({ name: user, params: { userId } }) // - /user/123 router.push({ path: /user/${userId} }) // - /user/123 // 下面这种写法不会生效 router.push({ path: /user, params: { userId } }) // - /user这一行为在源码中有明确对应normalizeLocationsrc/util/location.js在目标带有name时保留params并交给匹配器填充而走path分支时只解析path、query、hashparams不会参与路径拼接。同样的规则也适用于router-link的to属性。回调参数 onComplete / onAbort从2.2.0开始你可以选择性地为router.push或router.replace传入onComplete与onAbort作为第二、第三参数onComplete导航成功完成后触发此时所有异步守卫 hooks 均已 resolveonAbort导航被中止时触发典型场景包括导航到与当前相同的路由或在新导航完成之前又发起了另一次导航。3.1.0返回 Promise从3.1.0开始如果省略第二、第三参数且环境支持 Promiserouter.push/router.replace会返回一个 Promise。这一行为在 src/router.js 中可以直接看到push (location, onComplete, onAbort) { if (!onComplete !onAbort typeof Promise ! undefined) { return new Promise((resolve, reject) { this.history.push(location, resolve, reject) }) } else { this.history.push(location, onComplete, onAbort) } }因此两种风格均可使用// 回调风格2.2.0 this.$router.push(/foo, () { /* 完成 */ }, err { /* 中止 */ }) // Promise 风格3.1.0 this.$router.push(/foo).then(() { /* 完成 */ }).catch(err { /* 失败 */ })单元测试 test/unit/specs/api.spec.js 对两种风格均有覆盖既验证传入回调时push返回undefined且回调被触发也验证省略回调时返回 Promise 并支持.catch/.finally链式调用。导航失败的判别进阶由于push返回的 Promise 在导航失败时会 reject控制台可能出现Uncaught (in promise) Error。vue-router 从3.4.0起提供isNavigationFailure与NavigationFailureType详见 docs/guide/advanced/navigation-failures.md用于精确区分失败类型。这些类型定义在 src/util/errors.jsredirected守卫中调用next(新地址)发生重定向aborted守卫中调用next(false)中止导航cancelled当前导航未完成时又发起了新导航duplicated目标与当前路由相同冗余导航被拦截错误名NavigationDuplicated。import VueRouter from vue-router const { isNavigationFailure, NavigationFailureType } VueRouter router.push(/admin).catch(failure { if (isNavigationFailure(failure, NavigationFailureType.redirected)) { showToast(请先登录以访问管理后台) } })所有导航失败对象都携带to与from属性反映失败导航的目标与来源均为规范化后的路由位置。router.replace(location, onComplete?, onAbort?)router.replace的行为与router.push几乎一致唯一区别是它不会向历史栈推入新记录而是替换当前记录——因此用户点击浏览器后退按钮不会回到替换前的页面。它的声明式对应物是带replace属性的router-link声明式编程式router-link :to... replacerouter.replace(...)replace同样支持onComplete/onAbort回调2.2.0与 Promise 返回3.1.0同样受params与path的规则约束。典型应用场景包括登录成功后的页面替换避免用户后退回到登录页、表单提交后的结果页跳转等。router.go(n)router.go接收一个整数参数表示在历史栈中前进或后退多少步与window.history.go(n)语义一致。示例// 前进一条记录等同于 history.forward() router.go(1) // 后退一条记录等同于 history.back() router.go(-1) // 前进 3 条记录 router.go(3) // 如果历史栈中没有足够记录则静默失败 router.go(-100) router.go(100)vue-router 还提供了便捷方法router.back()与router.forward()在 src/router.js 中它们分别实现为this.go(-1)与this.go(1)可直接用于返回上一页前进一页的按钮场景。历史操作与 window.history 的对应关系你可能会注意到router.push、router.replace、router.go分别对应window.history.pushState、window.history.replaceState和window.history.go它们正是对浏览器 History API 的模仿与封装。因此如果你熟悉 [MDN 上的 History API 文档]上手 vue-router 的历史操作会非常容易。具体对应关系汇总vue-router 方法底层能力说明router.pushwindow.history.pushState推入新历史记录router.replacewindow.history.replaceState替换当前历史记录router.go(n)window.history.go(n)按步数前进/后退router.back()/router.forward()history.back()/history.forward()后退/前进一步三种模式下的一致性保证值得强调的是vue-router 的导航方法push、replace、go在路由的所有工作模式history、hash、abstract下行为一致这得益于 src/history 目录下三个子类对统一接口的实现。从源码可以印证各模式的具体差异history模式src/history/html5.jspush/replace在transitionTo成功后分别调用pushState/replaceState修改 URL由 src/util/push-state.js 封装内部处理浏览器兼容go直接委托window.history.go(n)同时监听popstate事件响应用户前进/后退。hash模式src/history/hash.js在支持pushState的浏览器上复用pushState/replaceState更新#之后的片段否则退化为修改window.location.hashreplace对应window.location.replace监听事件按能力选择popstate或hashchange。abstract模式src/history/abstract.js不依赖浏览器 API内部维护stack数组与index指针push截断后续记录后追加新路由replace原地替换go则在越界时静默返回。该模式常用于非浏览器环境Node.js、SSR、Electron 等。可以推断这种统一 API 分模式实现的架构是导航方法在任何模式下表现一致的根本原因。在 src/router.js 的构造函数中也可以看到模式选择的逻辑默认hash模式非浏览器环境强制abstracthistory模式在不支持pushState时自动回退到hash。编程式导航的完整实战示例结合仓库示例 examples/basic/app.js一个完整的使用流程如下在根实例中注入router然后在组件方法里通过this.$router.push完成跳转并利用onComplete回调执行后续逻辑import Vue from vue import VueRouter from vue-router Vue.use(VueRouter) const router new VueRouter({ mode: history, routes: [ { path: /, component: Home }, { path: /foo, component: Foo } ] }) new Vue({ router, methods: { navigateAndIncrement () { const increment () this.n if (this.$route.path /) { this.$router.push(/foo, increment) // 跳转成功后自增计数 } else { this.$router.push(/, increment) } } } }).$mount(#app)同路由仅参数变化的场景注意如果目标与当前路由相同只有params发生变化例如从/users/1导航到/users/2组件实例会被复用此时需要借助组件内的beforeRouteUpdate守卫来响应变化例如重新拉取用户信息详见 docs/guide/essentials/dynamic-matching.md。同时这种导航到相同路由的情况正是onAbort回调或 Promise 的 reject会被触发的典型场景对应的失败类型为duplicated。小结编程式导航是 vue-router 提供的能力完备、与声明式router-link完全对等的导航途径router.push推入新历史记录router.replace替换当前记录router.go(n)以及back/forward在历史栈中移动location参数支持字符串与对象命名路由配合params传参最可靠path存在时params被忽略2.2.0 支持onComplete/onAbort回调3.1.0 支持 Promise 风格并可通过isNavigationFailure精确处理失败所有导航方法在history、hash、abstract三种模式下行为一致底层分别由 src/history/html5.js、src/history/hash.js、src/history/abstract.js 实现。如需进一步验证上述行为可阅读单元测试 test/unit/specs/api.spec.js覆盖 push/replace 的回调与 Promise 两种风格与 test/unit/specs/abstract-history.spec.js覆盖 abstract 模式下的go栈操作以及运行 examples/basic 示例观察真实跳转效果。【免费下载链接】vue-router The official router for Vue 2项目地址: https://gitcode.com/gh_mirrors/vu/vue-router创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门