Vue-Router 实现思路
- 创建VueRouter插件,实现静态方法install。为什么要install静态方法呢?因为我们在Vue中注册VueRouter插件,即
Vue.use(VueRouter)
时,Vue内部先判断传进来的VueRouter是函数还是对象,函数则执行,对象则调用其install方法,并会将Vue对象作为参数传入。
- 判断插件是否已经被加载。(只要加载一次)
- 当Vue加载的时候把传入的router对象挂载到Vue实例上。(只执行一次)
- 当我们将路由信息放入VueRouter实例化时,即
const router = new VueRouter({ routes })
需要在VueRouter插件内部初始化routeMap,初始化组件router-link router-view等工作
- initRouteMap() 遍历所有路由信息,把组件和路由的映射记录到 routeMap 对象中
- initComponent() 通过Vue.component创建router-link和router-view组件
- initEvent() 注册 popstate 事件,当路由地址发生变化,重新记录当前的路径
Vue-Router 代码实现
let _Vue = null
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.initRouteMap()
this.initComponent()
this.initEvent()
}
initRouteMap() {
if (this.options.routes) {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component
})
}
}
initComponent() {
_Vue.component('router-link', {
props: {
to: String
},
render(h) {
return h('a', {
attrs: {
href: this.to
},
on: {
click: this.clickHandle
}
}, [this.$slots.default])
},
methods: {
clickHandle(e) {
history.pushState({}, "", this.to)
this.$router.data.current = this.to
e.preventDefault()
}
}
})
const self = this
_Vue.component('router-view', {
render(h) {
const comp = self.routeMap[self.data.current]
return h(comp)
}
})
}
initEvent() {
window.addEventListener("popstate", () => {
this.data.current = location.pathname
})
}
}
export default VueRouter