自己实现vue-router
实现基本路由功能
创建一个简单的路由系统需要定义路由映射和监听URL变化。以下是一个基础实现:
class VueRouter {
constructor(options) {
this.routes = options.routes || []
this.mode = options.mode || 'hash'
this.current = window.location.hash.slice(1) || '/'
this.routeMap = this.createMap(this.routes)
window.addEventListener('load', () => {
if (!window.location.hash) {
window.location.hash = '/'
}
})
window.addEventListener('hashchange', () => {
this.current = window.location.hash.slice(1)
})
}
createMap(routes) {
return routes.reduce((map, route) => {
map[route.path] = route.component
return map
}, {})
}
}
实现路由视图组件
创建<router-view>组件用于显示匹配的组件内容:
Vue.component('router-view', {
render(h) {
const current = this.$router.current
const routeComponent = this.$router.routeMap[current]
return h(routeComponent)
}
})
实现路由链接组件
创建<router-link>组件用于导航:
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('a', {
attrs: {
href: '#' + this.to
}
}, this.$slots.default)
}
})
安装路由插件
将路由器实例注入Vue原型:

let _Vue
VueRouter.install = function(Vue) {
_Vue = Vue
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
}
实现嵌套路由
支持嵌套路由需要递归匹配路径:
function createRouteMap(routes, pathMap = {}, parentPath = '') {
routes.forEach(route => {
const normalizedPath = parentPath + route.path
pathMap[normalizedPath] = route.component
if (route.children) {
createRouteMap(route.children, pathMap, normalizedPath)
}
})
return pathMap
}
实现动态路由
支持动态路径参数:

function createRouteMap(routes) {
const pathList = []
const pathMap = {}
routes.forEach(route => {
addRouteRecord(pathList, pathMap, route)
})
return {
pathList,
pathMap
}
}
function addRouteRecord(pathList, pathMap, route, parent) {
const path = parent ? `${parent.path}/${route.path}` : route.path
const record = {
path,
component: route.component,
parent
}
if (!pathMap[path]) {
pathList.push(path)
pathMap[path] = record
}
if (route.children) {
route.children.forEach(child => {
addRouteRecord(pathList, pathMap, child, record)
})
}
}
实现导航守卫
添加全局前置守卫功能:
class VueRouter {
constructor(options) {
this.beforeHooks = []
}
beforeEach(fn) {
this.beforeHooks.push(fn)
}
navigateTo(path) {
const hooks = this.beforeHooks
const from = this.current
const to = path
runQueue(hooks, from, to, () => {
this.current = to
window.location.hash = to
})
}
}
function runQueue(queue, from, to, cb) {
function next(index) {
if (index >= queue.length) return cb()
const hook = queue[index]
hook(from, to, () => {
next(index + 1)
})
}
next(0)
}
实现HTML5历史模式
支持history API的路由模式:
class VueRouter {
constructor(options) {
this.mode = options.mode || 'hash'
if (this.mode === 'history') {
this.current = window.location.pathname
window.addEventListener('popstate', () => {
this.current = window.location.pathname
})
} else {
// hash模式实现
}
}
push(path) {
if (this.mode === 'history') {
window.history.pushState({}, '', path)
this.current = path
} else {
window.location.hash = path
}
}
}
完整使用示例
将各部分组合后的使用方式:
const router = new VueRouter({
mode: 'hash',
routes: [
{ path: '/', component: Home },
{ path: '/about', component: About },
{
path: '/user',
component: User,
children: [
{ path: 'profile', component: Profile }
]
}
]
})
router.beforeEach((from, to, next) => {
console.log(`Navigating from ${from} to ${to}`)
next()
})
new Vue({
router,
el: '#app'
})






