@新到码手简简单单手撸vue-router
前言
例如:随着前端内卷严重的开始越来越多的面试都要研究底层原理,此次写作只为小白,有问题及时私信。
1.注释全写在上面了,不懂的可以私信我。
let _Vue = null
export default class VueRouter {
static install (vue) {
// 判断是否进行install挂载
if (VueRouter.install.installed) {
return //如果挂载了就return 出去
}
VueRouter.install.installed = true //将其设置为true 进行判断
_Vue = vue
_Vue.mixin({ //初始化时候混入到vue实例中
beforeCreate () {
if (this.$options.router) {
_Vue.prototype.$router = this.$options.router //原型上绑定上router实例
this.$options.router.init() //给router绑定上方法
}
}
})
}
constructor (options) {
this.options = options //配置对象
this.routeMap = {} //路由映射关系表
this.data = _Vue.observable({ // 创建一个响应数据 (就是路径)
current: '/'
})
}
init () {
this.createRouteMap() //创建路由关系映射对象表
this.initComponents(_Vue) //绑定上route-link组件 、route-view组件
this.initEvent()// 使用浏览器的方法监听hash值的变化
}
createRouteMap () {
this.options.routes.forEach(route => {
this.routeMap[route.path] = route.component //路径中每个组件实例绑定到每个路径形成映射关系
})
}
initComponents (Vue) {
Vue.component('router-link', {
props: {
to: String //接受一个路径
},
render (h) { //渲染a标签
return h('a', {
attrs: {
href: this.to
},
on: {
click: this.clickHandler //绑定事件
}
}, [this.$slots.default])// 默认插槽进行渲染
},
methods: {
clickHandler (e) {
history.pushState({}, '', this.to) //前往这个路径 向当前浏览器会话的历史堆栈中添加一个状态(state)。
this.$router.data.current = this.to //这个响应式数据变化,导致下方view重新渲染对应的组件
e.preventDefault() //阻止默认事件
}
}
// template: '<a :href="to"><slot></slot></a>'
})
const self = this
// router 组件
Vue.component('router-view', {
render (h) {
const component = self.routeMap[self.data.current] //current路径 通过路径找到对应的组件实例
console.log(component)
return h(component) //渲染到该 router-view上
}
})
}
initEvent () {
// 监听histroy栈变化(浏览器前进后退触发)
window.addEventListener('popstate', () => {
this.data.current = window.location.pathname //这里一变化上面 的view就把对应的组件显示出来
})
}
}
总结
有不足的地方恳请批评指正,谢谢咯。