Appearance
Vue Router 源代码导览
项目结构
vue-router-course/
├── 04-core-feature/ # 核心功能实现
│ ├── src/
│ │ ├── router.js # 路由器
│ │ ├── route.js # 路由记录
│ │ ├── history.js # 历史管理
│ │ └── matcher.js # 路由匹配
│ ├── test/
│ │ ├── router.test.js
│ │ ├── route.test.js
│ │ ├── history.test.js
│ │ └── matcher.test.js
│ ├── package.json
│ └── README.md
├── 05-lesson-plan.md # 课程计划
├── 01-intro.md # 背景研究
├── 02-arch.md # 架构分析
└── 03-code-walkthrough.md # 源代码导览核心文件解析
1. router.js - 路由器
文件路径: src/router.js
核心功能:
- 路由匹配
- 导航管理
- 历史管理
关键代码:
javascript
// 路由器
export class Router {
constructor(options = {}) {
this.routes = options.routes || []
this.currentRoute = null
this.history = createHistory(options.mode || 'hash')
this.beforeEachHooks = []
this.afterEachHooks = []
this.init()
}
// 初始化路由
init() {
this.history.listen((location) => {
this.handleRouteChange(location)
})
this.handleRouteChange(this.history.getCurrentLocation())
}
// 处理路由变化
handleRouteChange(location) {
const route = this.match(location)
this.runBeforeEachHooks(route, () => {
this.currentRoute = route
this.runAfterEachHooks(route)
})
}
// 匹配路由
match(location) {
const matcher = new Matcher(this.routes)
return matcher.match(location)
}
// 导航到指定路由
push(location) {
this.history.push(location)
}
// 替换当前路由
replace(location) {
this.history.replace(location)
}
// 返回上一页
go(n) {
this.history.go(n)
}
// 添加全局前置守卫
beforeEach(hook) {
this.beforeEachHooks.push(hook)
}
// 添加全局后置钩子
afterEach(hook) {
this.afterEachHooks.push(hook)
}
// 运行全局前置守卫
runBeforeEachHooks(route, callback) {
let index = 0
const next = () => {
if (index >= this.beforeEachHooks.length) {
callback()
return
}
const hook = this.beforeEachHooks[index++]
hook(route, this.currentRoute, next)
}
next()
}
// 运行全局后置钩子
runAfterEachHooks(route) {
this.afterEachHooks.forEach(hook => {
hook(route, this.currentRoute)
})
}
}设计要点:
- 支持多种历史模式
- 支持导航守卫
- 支持路由匹配
2. route.js - 路由记录
文件路径: src/route.js
核心功能:
- 存储路由配置
- 管理子路由
- 匹配路径
关键代码:
javascript
// 路由记录
export class RouteRecord {
constructor(record) {
this.path = record.path
this.component = record.component
this.name = record.name
this.children = record.children || []
this.props = record.props
this.meta = record.meta || {}
this.beforeEnter = record.beforeEnter
}
// 添加子路由
addChild(record) {
this.children.push(new RouteRecord(record))
}
// 获取所有子路由
getChildren() {
return this.children
}
}
// 路由对象
export class Route {
constructor(options = {}) {
this.path = options.path || '/'
this.name = options.name
this.params = options.params || {}
this.query = options.query || {}
this.hash = options.hash || ''
this.matched = options.matched || []
this.meta = options.meta || {}
}
// 创建完整路径
get fullPath() {
let path = this.path
if (Object.keys(this.query).length > 0) {
const query = new URLSearchParams(this.query).toString()
path += '?' + query
}
if (this.hash) {
path += '#' + this.hash
}
return path
}
}设计要点:
- 简单的路由配置
- 支持嵌套路由
- 支持自定义属性
3. history.js - 历史管理
文件路径: src/history.js
核心功能:
- 管理 URL 历史
- 监听 URL 变化
- 导航控制
关键代码:
javascript
// Hash 历史管理
export class HashHistory {
constructor() {
window.addEventListener('hashchange', this.handleHashChange.bind(this))
}
// 获取当前位置
getCurrentLocation() {
return window.location.hash.slice(1) || '/'
}
// 导航到指定路径
push(path) {
window.location.hash = path
}
// 替换当前路径
replace(path) {
const url = new URL(window.location)
url.hash = path
window.history.replaceState(null, '', url)
}
// 前进或后退
go(n) {
window.history.go(n)
}
// 监听路由变化
listen(callback) {
this.callback = callback
}
// 处理 hash 变化
handleHashChange() {
if (this.callback) {
this.callback(this.getCurrentLocation())
}
}
}
// HTML5 历史管理
export class HTML5History {
constructor() {
window.addEventListener('popstate', this.handlePopState.bind(this))
}
// 获取当前位置
getCurrentLocation() {
return window.location.pathname
}
// 导航到指定路径
push(path) {
window.history.pushState(null, '', path)
}
// 替换当前路径
replace(path) {
window.history.replaceState(null, '', path)
}
// 前进或后退
go(n) {
window.history.go(n)
}
// 监听路由变化
listen(callback) {
this.callback = callback
}
// 处理 popstate 事件
handlePopState() {
if (this.callback) {
this.callback(this.getCurrentLocation())
}
}
}
// 创建历史管理器
export function createHistory(mode) {
switch (mode) {
case 'hash':
return new HashHistory()
case 'html5':
return new HTML5History()
default:
return new HashHistory()
}
}设计要点:
- 支持多种历史模式
- 监听 URL 变化
- 提供导航控制
4. matcher.js - 路由匹配
文件路径: src/matcher.js
核心功能:
- 匹配路径
- 解析参数
- 构建路由对象
关键代码:
javascript
// 路由匹配器
export class Matcher {
constructor(routes) {
this.routes = this.createRouteRecords(routes)
}
// 创建路由记录
createRouteRecords(routes, parent = null) {
return routes.map(route => {
const record = new RouteRecord({
...route,
parent
})
if (route.children) {
record.children = this.createRouteRecords(route.children, record)
}
return record
})
}
// 匹配路径
match(path) {
const matched = this.matchRoute(path, this.routes)
if (!matched) {
return null
}
return new Route({
path: matched.path,
params: matched.params,
matched: matched.records
})
}
// 匹配路由
matchRoute(path, routes) {
const segments = path.split('/').filter(Boolean)
let currentRoutes = routes
const matchedRecords = []
let matchedParams = {}
let matchedPath = ''
for (const segment of segments) {
let matched = null
for (const route of currentRoutes) {
const result = this.matchPathSegment(segment, route.path)
if (result) {
matched = { route, params: result.params }
break
}
}
if (!matched) {
return null
}
matchedRecords.push(matched.route)
Object.assign(matchedParams, matched.params)
matchedPath += '/' + segment
currentRoutes = matched.route.children || []
}
return {
path: matchedPath || '/',
params: matchedParams,
records: matchedRecords
}
}
// 匹配路径段
matchPathSegment(segment, routePath) {
// 精确匹配
if (segment === routePath) {
return { params: {} }
}
// 动态参数匹配
const paramMatch = routePath.match(/^:([^/]+)$/)
if (paramMatch) {
return { params: { [paramMatch[1]]: segment } }
}
return null
}
}设计要点:
- 支持动态参数
- 支持嵌套路由
- 精确的路径匹配
关键设计决策
1. 分离历史管理
原因:
- 支持多种历史模式
- 易于扩展
- 职责分离
实现:
javascript
class HashHistory { }
class HTML5History { }
function createHistory(mode) {
switch (mode) {
case 'hash': return new HashHistory()
case 'html5': return new HTML5History()
}
}2. 使用守卫系统
原因:
- 控制导航流程
- 支持权限验证
- 支持数据预取
实现:
javascript
router.beforeEach((to, from, next) => {
// 守卫逻辑
next()
})3. 嵌套路由
原因:
- 支持复杂布局
- 支持组件嵌套
- 支持参数传递
实现:
javascript
{
path: '/user',
component: User,
children: [
{
path: 'profile',
component: Profile
}
]
}测试策略
单元测试
javascript
import { describe, it } from 'node:test'
import assert from 'node:assert'
import { Router } from '../src/router.js'
describe('Router 测试', () => {
it('应该创建路由器', () => {
const router = new Router({
routes: [
{ path: '/', component: Home }
]
})
assert.ok(router)
})
it('应该匹配路由', () => {
const router = new Router({
routes: [
{ path: '/', component: Home }
]
})
const route = router.match('/')
assert.ok(route)
})
})总结
Vue Router 的源代码体现了以下设计原则:
- 模块化:清晰的模块划分
- 灵活性:支持多种路由模式
- 可扩展:支持自定义路由和守卫
- 易于测试:提供清晰的接口
理解源代码有助于更好地使用和优化 Vue Router。
参考资源

扫描二维码关注"架构师AI杜"公众号,获取更多技术内容和最新动态
