Vue Router实现原理
1) 基本原理
- hash
- URL 中 # 后面的内容作为路径地址
- 监听 hashchange 事件
- 根据当前路由地址找到对应组件重新渲染
- history
- 通过 history.pushState() 方法改变地址栏
- 监听 popState 事件
- 根据当前路由地址找到对应组件重新渲染
2)模拟实现
1)Vue 的构建版本
- 运行时版:不支持 template 模板,需要打包的时候提前编译(vue-cli 创建的项目默认是 运行时版)
- 完整版:包含运行时和编译器,体积比运行时版大 10k 左右,程序运行的时候把模板转换成 render 函数
import Vue from 'vue'
console.dir(Vue)
let _Vue = null
export default class VueRouter {
static install(Vue) {
if (VueRouter.install.installed) {
return;
}
VueRouter.install.installed = true
_Vue = Vue
_Vue.mixin({
beforeCreate() {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router
}
}
})
}
constructor(options) {
this.options = options
this.routeMap = {}
this.data = _Vue.observable({
current: "/"
})
this.init()
}
init() {
this.createRouteMap()
this.initComponent(_Vue)
this.initEvent()
}
createRouteMap() {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
});
}
initComponent(Vue) {
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('a', {
attrs: {
href: this.to,
},
on: {
click: this.clickHandler
},
}, [this.$slots.default])
},
methods: {
clickHandler(e) {
history.pushState({}, '', this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
});
const self = this;
Vue.component('router-view', {
render(h) {
const component = self.routeMap[self.data.current]
return h(component)
}
})
}
initEvent () {
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
}