开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
前言
第一篇内容开始,本篇主要总结一下项目入口文件到代码入口文件一个过程,并记录一下调试过程(部分)
核心地带
在上一篇内容提到的src/platforms/web/entry-runtime-with-compiler.js文件中,存在Vue构造函数的引用
现在打开
src/platforms/web/runtime/index.js可以看到该文件中,大部分都是对于Vue上属性的赋值定义
其中该文件中Vue的来源:
src/platforms/web/runtime/index.js
extend(Vue.options.directives, platformDirectives) // platformDirectives: 全局指令model ,show
extend(Vue.options.components, platformComponents) // platformComponents: 全局组件Transition,TransitionGroup
// 但是不太清楚为啥仅仅吧model show 放在这里,后续看一下为啥???
Vue.prototype.__patch__ = inBrowser ? patch : noop
Vue.prototype.$mount = function (...) {...}
在src/core/index.js在该文件中,正式进入到Vue的核心地带,Vue也是从此暴露出去的。【vue的定义是在src/core/instance/index.js】,
core文件夹内容详谈
src/core/instance/index.js 中核心内容
function Vue (options) {
....
this._init(options)
}
initMixin(Vue) // Vue.prototype._init
stateMixin(Vue) // Vue.prototype.$set,Vue.prototype.$delete, Vue.prototype.$watch,
eventsMixin(Vue) // Vue.prototype.$on,Vue.prototype.$once, Vue.prototype.$off, Vue.prototype.$emit
lifecycleMixin(Vue) // Vue.prototype._update,Vue.prototype.$forceUpdate, Vue.prototype.$destroy,
renderMixin(Vue) // Vue.prototype.$nextTick, Vue.prototype._render
export default Vue
src/core/index.js核心代码
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
...
initGlobalAPI(Vue)
...
下面探究一下:initGlobalAPI 这个方法中干了什么
- 主要是增加了全局的组件,指令方法
小总结
写到这个地方,把上面的过程总结一下:
Vue基本代码的执行在源码中的核心流程
像我们前端平常开发Vue项目,已经了解了大部分的Vue的一些技术点:数据双向绑定,监听器,计算属性,生命周期,mixin, 组件传值,模板语法等等
以前看过一位大佬的博客 对于源码的总结,很适合我这种初级手了解,现在我根据自己的理解先对代码运行时进行一个简单的小总。
【下图主要是created之前的一个过程】(画的过于潦草,见谅)
在代码主要的部分还是init 数据、方法、计算属性,监听器的内容,而这部分出现在initState方法中,下面就继续讨论initState方法
new Dep():src/core/observer/dep.js
Dep非常重要,对于响应式,它与要实现响应式功能的数据对象和对象属性关联
使用的实例化场景有两个地方:
- defineReactive(): url:
src/core/observer/index.js(135行) - Observer 构造函数内:url:
src/core/observer/index.js(37行)
这样Observer对象与Dep对象一对一关联起来
此处经过处理后的对象属性具有响应式功能,且每个属性通过必报中保存了一份Dep对象及其他必要信息,最后对象的属性也与Dep对象同样实现了一对一的关联
Dep源码
export default class Dep {
static target: ?Watcher; // 静态变量,保存watcher类型对象
id: number; // 对象的id
subs: Array<Watcher>; // 订阅者数组,元素即watcher对象
constructor () {
this.id = uid++
this.subs = []
}
addSub (sub: Watcher) { // 添加订阅者(对象的属性)
this.subs.push(sub)
}
removeSub (sub: Watcher) { // 删除订阅者
remove(this.subs, sub)
}
depend () { // 依赖收集
if (Dep.target) {
Dep.target.addDep(this) // addDep()是watcher构造函数中的方法,用于在subs添加内容
}
}
notify () { // 通知订阅者,更新事件
const subs = this.subs.slice()
...
for(let i=0, l=subs.length;i<l;i++) {
sub[i].update()
}
}
}
Dep.target = null
const targetStack = []
// watcher 对象
export function pushTarget (target: ?Watcher) { // 入栈
debugger
targetStack.push(target)
Dep.target = target
}
export function popTarget () { // 出栈
debugger
targetStack.pop()
Dep.target = targetStack[targetStack.length - 1]
}
后记
本文仅作为自己一个阅读记录,具体还是要看大佬们的文章 下一篇:我的源码学习之路(二)---vue-2.6.14