# vue-router路由hash模式实现以及原理
# 原理
- window可监听 hashchange 事件(url后面哈希值即 #后面值的变化)
# 简单实现目标
- 实现挂载 $router
- 实现两个全局组件
router-link和router-view
# 实现挂载 $router
class VueRouter {
constructor(options) {
this.$options = options
// 声明一个响应式属性
Vue.util.defineReactive(this, 'currentPath', '/')
// 监听hash值的变化
window.addEventListener('hashchange', this.onHashChange.bind(this))
// 保存路由表
this.routerMap = {}
this.$options.routes.forEach(route => {
this.routerMap[route.path] = route
})
}
onHashChange() {
// 简单设置 currentPath 属性
this.currentPath = window.location.hash.slice(1)
}
}
// Vue插件需要声明一个install方法
VueRouter.install = function (Vue) {
// 全局混入beforeCreate生命周期方法
Vue.mixin({
beforeCreate() {
// 只要在Vue根实例中挂载,利用只有根实例选项上有router属性找到根实例
if (this.$options.router) {
Vue.prototype.$router = this.$options.router
}
}
})
}
# 实现两个全局组件 router-link 和 router-view
# router-link 组件
export default {
name: 'router-link',
props: {
to: {
type: String,
default: ''
}
},
render(h) {
// 利用render函数,生产一个a标签, href属性值为 #/about
return h('a', { attrs: { href: '#' + this.to } }, this.$slots.default)
}
}
# router-view 组件
export default {
name: 'router-view',
render(h) {
// component存放当前路由对应的组件
const component = null
// currentPath 是响应的,值改变时,此处render会重新执行
const { routerMap, currentPath } = this.$router
// 匹配对应的组件
component = routerMap[currentPath] ? routerMap[currentPath].component : null
return h(component)
}
}