vue-router的实现原理
hash原理
- 将url#后的内容作为路径地址
- 监听hashchange事件
- 通过当权路由地址找到对应组件重新渲染
history原理:
- 通过history.pushstate() 改变地址栏
- 监听popstate事件
- 通过当前路由地址找到对应组件重新渲染
代码实现
从代码中可以看出
- VueRouter是一个构造函数,有个install静态方法,当Vue.use(VueRouter)时执行
- VueRouter的构造器接收一个对象为参数,这个对象包括mode和routes等属性
- 创建Vue实例时,将VueRouter实例作为参数传入,使Vue可直接调用 router
- VueRouter 有两个自定义组件,router-link、router-view
VueRouter类图
简单实现history模式代码
export default class VueRouter{
option = null
data = null
routerMap = null
static install(Vue) {
// 用mixin混入,将$router、$route属性添加到的vue实例
Vue.mixin({
beforeCreate() {
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
this.$options.router.init(Vue)
}
}
})
}
constructor(option) {
this.option = option
this.routerMap = {}
this.data = {}
}
// 初始化
init(Vue) {
// 将data 变为响应式
this.data = Vue.observable({current: window.location.pathname})
this.initRouteMap()
this.initComonents(Vue)
this.initEvent()
}
// 初始化routeMap,将路由地址和路由组件对应,方便切换路由时获取组件
initRouteMap(){
console.log(this.option.routes);
this.option.routes.forEach(element => {
this.routerMap[element.path] = element.component
});
}
// 初始化自定义组件router-link、router-view
initComonents(Vue) {
let self = this
Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('a', {
attr: {
href: this.to
},
on: {
click: (e) => {
// 阻止a标签的默认事件,用history.pushState来改变地址栏
history.pushState(null, "", this.to)
// data是响应式的,当data.current改变时,触发router-view的改变
self.data.current = this.to
e.preventDefault()
}
}
}, [this.$slots.default])
}
})
Vue.component('router-view', {
render(h) {
return h(self.routerMap[self.data.current])
}
})
}
// 初始化事件,监听popState 事件,当浏览器切换历史路径(后退、前进)时触发,切换组件
initEvent() {
// 通过router-link切换路由时,不会触发popstate
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname
})
}
}