源码这个东西对于实际的工作其实没有立竿见影的效果,不会像那些针对性极强的文章一样看了之后就立马可以运用到实际项目中,产生什么样的效果,源码的作用是一个潜移默化的过程,它的理念、设计模式、代码结构等看了之后可能不会立即知识变现(或者说变现很少),而是在日后的工作过程中悄无声息地发挥出来,你甚至都感觉不到这个过程
另外,优秀的源码案例,例如 vue
、react
这种,内容量比较庞大,根本不是三篇五篇十篇八篇文章就能说完的,而且写起来也很难写得清楚,也挺浪费时间的,而如果只是分析其中一个点,例如 vue
的响应式,类似的文章也已经够多了,没必要再 repeat
所以我之前没专门写过源码分析的文章,只是自己看看,不过最近闲来无事看了 vue-router
的源码,发现这种插件级别的东西,相比 vue
这种框架级别的东西,逻辑简单清晰,没有那么多道道,代码量也不多,但是其中包含的理念等东西却很精炼,值得一写,当然,文如其名,只是概览,不会一行行代码分析过去,细节的东西还是要自己看看的
vue.use
vue
插件必须通过 vue.use
进行注册,vue.use
的代码位于 vue
源码的 src/core/global-api/use.js
文件中,此方法的主要作用有两个:
- 对注册的组件进行缓存,避免多次注册同一个插件
if (installedPlugins.indexOf(plugin) > -1) {
return this
}
- 调用插件的
install
方法或者直接运行插件,以实现插件的install
if (typeof plugin.install === 'function') {
plugin.install.apply(plugin, args)
} else if (typeof plugin === 'function') {
plugin.apply(null, args)
}
路由安装
vue-router
的 install
方法位于 vue-router
源码的src/install.js
中
主要是通过 vue.minxin
混入 beforeCreate
和 destroyed
钩子函数,并全局注册 router-view
和 router-link
组件
// src/install.js
Vue.mixin({
beforeCreate () {
if (isDef(this.$options.router)) {
this._routerRoot = this
this._router = this.$options.router
this._router.init(this)
Vue.util.defineReactive(this, '_route', this._router.history.current)
} else {
this._routerRoot = (this.$parent && this.$parent._routerRoot) || this
}
registerInstance(this, this)
},
destroyed () {
registerInstance(this)
}
})
...
// 全局注册 `router-view` 和 `router-link`组件
Vue.component('RouterView', View)
Vue.component('RouterLink', Link)
路由模式
vue-router
支持三种路由模式(mode
):hash
、history
、abstract
,其中 abstract
是在非浏览器环境下使用的路由模式,例如weex
路由内部会对外部指定传入的路由模式进行判断,例如当前环境是非浏览器环境,则无论传入何种mode
,最后都会被强制指定为 abstract
,如果判断当前环境不支持 HTML5 History
,则最终会被降级为 hash
模式
// src/index.js
let mode = options.mode || 'hash'
this.fallback = mode === 'history' && !supportsPushState && options.fallback !== false
if (this.fallback) {
mode = 'hash'
}
if (!inBrowser) {
mode = 'abstract'
}
最后会对符合要求的 mode
进行对应的初始化操作
// src/index.js
switch (mode) {
case 'history':
this.history = new HTML5History(this, options.base)
break
case 'hash':
this.history = new HashHistory(this, options.base, this.fallback)
break
case 'abstract':
this.history = new AbstractHistory(this, options.base)
break
default:
if (process.env.NODE_ENV !== 'production') {
assert(false, `invalid mode: ${
mode}`)
}
}
路由解析
通过递归的方式来解析嵌套路由
// src/create-route-map.js
function addRouteRecord