文章主题: 全面掌握 Vue-router 的使用和原理
发展历史
在 B/S(浏览器/服务器)架构开发中,传统的路由机制通常依赖后端路由,每次用户访问不同页面(如 index.html、detail.html、editor.html)时,浏览器都会向服务器发送请求,服务器返回对应的 HTML 文件。这种方式虽然简单,但随着应用规模的扩大,存在明显的问题,如页面刷新导致用户体验不佳、服务器压力增加等。
为了解决这些问题,前端导航(单页面应用,SPA)逐渐发展起来。在 SPA 中,整个应用加载在一个 HTML 页面内,路由由前端 JavaScript 框架(如 Vue.js、React、Angular)管理。用户在不同视图间切换时,不需要重新加载页面,而是通过动态更新页面内容,实现更流畅的用户体验。然而,SPA 也带来了一些挑战,如初次加载时间较长、SEO 优化困难等。为此,现代前端框架通常结合服务端渲染(SSR)和客户端渲染(CSR)技术<同构>, 兼顾性能和用户体验。
前端路由是单页应用(SPA)下的一种弥补传统文件即路径模式的方式。在传统的 B/S 架构中,每个页面都对应一个 HTML 文件,并通过浏览器的导航栏或超链接进行访问。但在单页应用中,整个应用加载在一个 HTML 页面内,所有页面的内容动态渲染,不再依赖于服务器返回的不同 HTML 文件。
前端路由通过在浏览器端管理 URL 和视图之间的映射关系,使得用户可以在不同的视图间进行切换,而不需要重新加载整个页面。这种方式实现了更流畅的用户体验,同时也降低了服务器的压力,但它需要前端框架提供的路由管理功能来实现。通过在 URL 中使用哈希路由或 HTML5 History API,前端路由能够捕获浏览器的导航事件,并根据路由规则动态加载对应的视图内容,从而实现页面间的无缝切换。
vue-router
框架介绍
Vue Router 是 Vue.js 官方的路由管理器,用于构建单页面应用(SPA)。它允许开发者通过定义路由来将不同的 URL 地址映射到不同的 Vue 组件,实现了页面间的切换和导航。Vue Router 提供了丰富的功能,包括嵌套路由、路由参数、路由导航守卫、动态路由匹配、命名路由等,同时与 Vue.js 生态系统无缝集成,为构建复杂的前端应用提供了强大的支持。
官网网站
vue-router 3.x
官方网站:
v3.router.vuejs.org/zh/installa…
源码地址:
vue-router 4.x
官方网站:
源码地址:
使用流程
安装 → 引入 → 实例化 → 配置相关属性 → 配置全局钩子 → 在 vue 实例中注册
安装
pnpm install vue-router
使用
main.js
import Vue from 'vue'
import router from './router/router.js'
import App from "./app.vue";
new Vue({
router, // 将 Vue Router 实例传递给 Vue 根实例
render: h => h(App)
}).$mount("#app");
router.js
import Router from "vue-router"
import Vue from "vue"
Vue.use(Router) // 在 Vue 实例中注册 Vue Router 插件
import HomeView from "@/views/HomeView.vue"
const router = new Router({
mode: 'history', // 路由模式 history | hash
routes:[
{
path:"/",
name:"home",
component: HomeView
},
{
path:"/home",
name:"home",
component: () => import("@/views/HomeView.vue","home") // 异步加载 & chunk
},
]
})
// 路由守卫 | 路由独享的守卫 | 组件内的守卫
// 全局前置守卫: 在导航被确认之前调用
router.beforeEach((to,from,next)=>{})
// 解析守卫:在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
router.beforeResolve((to,from,next)=>{})
// 全局后置钩子
router.afterEach((to,from,next)=>{})
export default router
扩展知识
说说如何给同一个网站配置不同的域名?
正向代理: 正向代理像是一个用户找一个中介去帮忙获取信息,它代表用户向服务器请求资源。
反向代理: 反向代理则像是一个服务员,它代表服务器向用户提供服务,隐藏了真实的服务器细节。
能力
路由模式 | 路由元信息 | 路由守卫 | 动态路由 | 组件传参 | 重定向 & 别名 & 404
过渡动效 | 滚动行为 | 路由懒加载的三种方式 |
函数式导航
使用 router 的实例方法,通过编写代码来实现导航。
router.push(location, onComplete?, onAbort?)
router.replace(location, onComplete?, onAbort?)
router.go(n)
router.push({path: "/"})
router.push({name: 'home', params:{}, query:{}})
扩展
params 不能使用的场景
在
router.push()方法中,使用{path: "/"}的方式不能用 params。这是因为在使用
{path: "/"}时,路由跳转是通过路径来匹配路由,而不是通过路由名称(name)。而 params 是在使用路由名称(name)进行路由跳转时传递参数的一种方式。因此,当使用{path: "/"}时,无法传递 params 参数。正确的做法是使用
{name: 'home', params:{}, query:{}},这样可以通过路由名称来跳转,并且可以传递 params 参数。
路由模式
在 Vue Router 中,hash 模式和 history 模式是两种不同的路由模式,它们主要区别在于 URL 的格式和对浏览器的兼容性。
hash 模式
在 hash 模式下,URL 中的路径会被表示为 #/ 后面的部分,例如:http://example.com/#/home。
这种模式在旧版浏览器中具有良好的兼容性,因为在 URL 中的 hash 值的改变不会导致页面的完全刷新,只会触发 hashchange 事件,从而实现单页面应用的路由切换。
但 hash 模式的 URL 可读性较差,且在 SEO 方面可能不够友好。
history 模式
在 history 模式下,URL 中的路径会像正常的 URL 一样,不带有 # 符号,例如:example.com/home。
这种模式通过 HTML5 History API 来管理路由,使得 URL 更加清晰易读,同时也更符合传统网站的 URL 结构。
但 history 模式需要服务器端的支持,因为在 history 模式下,服务器端需要配置当访问的 URL 不是一个文件时,返回同一个 HTML 页面,以便 Vue Router 可以处理路由。
实现这两种模式用到两个重要的API: window.onhashchange() 和 window.onpopstate() 。
思考问题: 什么情况下 URL 改变页面会刷新? 1. window.location 2. a 标签强制地址跳转(非hash改变)
即 hash 模式下, 通过改变URL中的 hash 值, 触发 onhashchange 监听 然后切换对应模块
而 history 模式, 通过 pushState() | replaceState() 改变当前路由状态, 触发 window.onpopstate() 从而实现模块切换
当浏览器处于 hash 模式下,URL 中的 hash 改变时,通过监听 ~~~~onhashchange~~~~ 事件,可以实现页面模块的切换,而不会导致页面的完全刷新。
在 history 模式下,通过使用 ~~~~pushState()~~~~ 或 ~~~~replaceState()~~~~ 方法改变当前的路由状态时,页面也不会完全刷新,只会更新对应的视图模块。
路由守卫
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。
手写 Router
数据流图 | 数据结构 | 相关 API
4.x 升级能力 🚀🚀
TODO