Skip to content

Commit d80eb56

Browse files
committed
patch 添加注释
1 parent bbd7062 commit d80eb56

File tree

18 files changed

+230
-25
lines changed

18 files changed

+230
-25
lines changed

src/core/instance/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,26 @@ function Vue(options) {
1111
if (__DEV__ && !(this instanceof Vue)) {
1212
warn('Vue is a constructor and should be called with the `new` keyword')
1313
}
14+
// 始化生命周期,添加父子组件关系,初始化事件、slot、注入、数据和provide
15+
// 并向当前实例挂载_events、$slots、props、methods、data、computed\_provide属性、给_provide设置父组件的_provide作为原型
1416
this._init(options)
1517
}
1618

1719
// 给Vue类 添加能力
1820
//@ts-expect-error Vue has function type
19-
// 添加初始化函数_init ,同时初始化生命周期,添加父子组件关系,初始化事件、slot、注入、数据和provide
20-
// 并向当前实例挂载_events、$slots、props、methods、data、computed\_provide属性、给_provide设置父组件的_provide作为原型
21+
// 添加初始化函数_init
2122
initMixin(Vue)
2223
//@ts-expect-error Vue has function type
24+
// Vue类上添加$props $data 的代理添加$watch方法
2325
stateMixin(Vue)
2426
//@ts-expect-error Vue has function type
27+
// 给Vue类上添加$on $off $once $emit方法
2528
eventsMixin(Vue)
2629
//@ts-expect-error Vue has function type
30+
// Vue类上挂载_update、$forceUpdate、$destroy方法
2731
lifecycleMixin(Vue)
2832
//@ts-expect-error Vue has function type
33+
// 挂载生成虚拟节点的方法_render和$nextTick,以及执行render函数需要的各种工具函数
2934
renderMixin(Vue)
3035

3136
export default Vue as unknown as GlobalAPI

src/core/instance/lifecycle.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,37 +70,44 @@ export function initLifecycle(vm: Component) {
7070
// 组件是否正在被销毁
7171
vm._isBeingDestroyed = false
7272
}
73-
73+
// Vue类上挂载_update、$forceUpdate、$destroy方法
7474
export function lifecycleMixin(Vue: typeof Component) {
7575
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {
7676
const vm: Component = this
7777
const prevEl = vm.$el
7878
const prevVnode = vm._vnode
79+
// 标识当前正在更新的组件实例,在patch、create-compoonent时使用
7980
const restoreActiveInstance = setActiveInstance(vm)
8081
vm._vnode = vnode
8182
// Vue.prototype.__patch__ is injected in entry points
8283
// based on the rendering backend used.
84+
// 之前没有虚拟节点,说明是第一次渲染
8385
if (!prevVnode) {
8486
// initial render
87+
// 生成真实DOM节点,将当前组件的挂载节点赋值给$el
8588
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)
8689
} else {
8790
// updates
8891
vm.$el = vm.__patch__(prevVnode, vnode)
8992
}
9093
restoreActiveInstance()
9194
// update __vue__ reference
95+
// 更新DOM元素和Vue实例之间的引用
9296
if (prevEl) {
9397
prevEl.__vue__ = null
9498
}
9599
if (vm.$el) {
96100
vm.$el.__vue__ = vm
97101
}
98102
// if parent is an HOC, update its $el as well
103+
// 在透明的高阶组件(高阶组件不渲染额外节点)的情况下,HOC没有额外的渲染内容,只是一个过渡的包装,为了保证HOC组件能够正确的访问实际DOM
99104
let wrapper: Component | undefined = vm
100105
while (
101106
wrapper &&
102107
wrapper.$vnode &&
103108
wrapper.$parent &&
109+
// _vnode 是当前组件的虚拟节点 $vnode 是当前组件在父组件中的虚拟节点
110+
// 通俗的说,_vode就是子组件的模版内容编译出的虚拟节点, $vode是父组件编译时的,子组件节点
104111
wrapper.$vnode === wrapper.$parent._vnode
105112
) {
106113
wrapper.$parent.$el = wrapper.$el
@@ -119,33 +126,42 @@ export function lifecycleMixin(Vue: typeof Component) {
119126

120127
Vue.prototype.$destroy = function () {
121128
const vm: Component = this
129+
// 已经开始销毁
122130
if (vm._isBeingDestroyed) {
123131
return
124132
}
133+
// 调用beforeDestroy钩子
125134
callHook(vm, 'beforeDestroy')
126135
vm._isBeingDestroyed = true
127136
// remove self from parent
128137
const parent = vm.$parent
129138
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
139+
// 从父组件中移除
130140
remove(parent.$children, vm)
131141
}
132142
// teardown scope. this includes both the render watcher and other
133143
// watchers created
134144
vm._scope.stop()
135145
// remove reference from data ob
136146
// frozen object may not have observer.
147+
// vmCount 记录了有多少个组件实例在使用这个响应式数据
148+
// 当组件销毁时,需要减少计数,表示少了一个使用者
149+
// 这是为了内存管理,当 vmCount 为 0 时,表示没有组件在使用这个响应式数据了
137150
if (vm._data.__ob__) {
138151
vm._data.__ob__.vmCount--
139152
}
140153
// call the last hook...
141154
vm._isDestroyed = true
142155
// invoke destroy hooks on current rendered tree
156+
// 新的vnode为null, 用来更新销毁后的视图
143157
vm.__patch__(vm._vnode, null)
158+
// 调用destroyed钩子
144159
// fire destroyed hook
145160
callHook(vm, 'destroyed')
146161
// turn off all instance listeners.
147162
vm.$off()
148163
// remove __vue__ reference
164+
// 当前节点和DOM、父节点的关系断开
149165
if (vm.$el) {
150166
vm.$el.__vue__ = null
151167
}

src/core/instance/render.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,19 @@ export function setCurrentRenderingInstance(vm: Component) {
9999

100100
export function renderMixin(Vue: typeof Component) {
101101
// install runtime convenience helpers
102+
// 编译生成的render函数中,所使用的各种工具函数挂载到Vue.prototype上
102103
installRenderHelpers(Vue.prototype)
103-
104+
// 挂载$nextTick函数
104105
Vue.prototype.$nextTick = function (fn: (...args: any[]) => any) {
105106
return nextTick(fn, this)
106107
}
107-
108+
// 挂载_render函数
108109
Vue.prototype._render = function (): VNode {
109110
const vm: Component = this
110111
const { render, _parentVnode } = vm.$options
111-
112+
// 如果有父节点且组件已挂载
112113
if (_parentVnode && vm._isMounted) {
114+
// 标准化作用域插槽的格式 合并新旧作用域插槽。子组件更新时,要对父组件传递过来的插槽内容重新合并
113115
vm.$scopedSlots = normalizeScopedSlots(
114116
vm.$parent!,
115117
_parentVnode.data!.scopedSlots,
@@ -131,8 +133,10 @@ export function renderMixin(Vue: typeof Component) {
131133
try {
132134
setCurrentInstance(vm)
133135
currentRenderingInstance = vm
136+
// 执行这个实例的render函数,生成虚拟节点
134137
vnode = render.call(vm._renderProxy, vm.$createElement)
135138
} catch (e: any) {
139+
// render 过程中报错
136140
handleError(e, vm, `render`)
137141
// return error render result,
138142
// or previous vnode to prevent render error causing blank component
@@ -149,6 +153,7 @@ export function renderMixin(Vue: typeof Component) {
149153
vnode = vm._vnode
150154
}
151155
} else {
156+
// 出错则使用旧的虚拟节点
152157
vnode = vm._vnode
153158
}
154159
} finally {
@@ -160,7 +165,9 @@ export function renderMixin(Vue: typeof Component) {
160165
vnode = vnode[0]
161166
}
162167
// return empty vnode in case the render function errored out
168+
// 如果生成的虚拟节点不是VNode的实例,警告
163169
if (!(vnode instanceof VNode)) {
170+
// 如果是多虚拟根节点,报错,使用空虚拟节点作为当前节点
164171
if (__DEV__ && isArray(vnode)) {
165172
warn(
166173
'Multiple root nodes returned from render function. Render function ' +

src/core/instance/state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,7 @@ export function stateMixin(Vue: typeof Component) {
415415
return this._props
416416
}
417417
if (__DEV__) {
418+
// data和props不能直接赋值
418419
dataDef.set = function () {
419420
warn(
420421
'Avoid replacing instance root $data. ' +

src/core/observer/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ export class Observer {
8787
}
8888
}
8989
}
90-
// 如果不是浅响应,需要对数组元素进行依赖收集
90+
// 如果不是浅响应,需要对数组元素observe
9191
if (!shallow) {
9292
this.observeArray(value)
9393
}
@@ -124,6 +124,7 @@ export class Observer {
124124
* returns the new observer if successfully observed,
125125
* or the existing observer if the value already has one.
126126
*/
127+
// 负责把对象整体变成响应式
127128
export function observe(
128129
value: any,
129130
shallow?: boolean,
@@ -150,6 +151,7 @@ export function observe(
150151
/**
151152
* Define a reactive property on an Object.
152153
*/
154+
// 负责把一个对象的属性变成响应式
153155
export function defineReactive(
154156
obj: object,
155157
key: string,
@@ -273,12 +275,14 @@ export function set(
273275
return
274276
}
275277
const ob = (target as any).__ob__
278+
// 如果原始对象是个数组
276279
if (isArray(target) && isValidArrayIndex(key)) {
277280
// 给原始数组设置长度
278281
target.length = Math.max(target.length, key)
279282
// 将key索引处的值替换成新值
280283
target.splice(key, 1, val)
281284
// when mocking for SSR, array methods are not hijacked
285+
// 对新的数组响应式
282286
if (ob && !ob.shallow && ob.mock) {
283287
observe(val, false, true)
284288
}
@@ -289,7 +293,7 @@ export function set(
289293
target[key] = val
290294
return val
291295
}
292-
// 如果target是Vue实例 或者 再被Observer劫持的情况下有vmCount,则不允许设置响应式属性 vm存在说明是根级别的data
296+
// 如果target是Vue实例 或者 再被Observer劫持的情况下有vmCount,则不允许设置响应式属性 vmCount存在说明多个实例使用这个对象作为根级别的data
293297
// 性能考虑:
294298
// 根级响应式数据的变化会触发整个组件树的重新渲染
295299
// 运行时添加根级属性可能导致不必要的性能开销

src/core/observer/traverse.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ function _traverse(val: any, seen: SimpleSet) {
4242
} else {
4343
keys = Object.keys(val)
4444
i = keys.length
45+
// 关键是这一行,对value[keys[i]]再次深层遍历,相当于获取响应式对象的属性,触发更新
4546
while (i--) _traverse(val[keys[i]], seen)
4647
}
4748
}

src/core/util/options.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,10 +550,13 @@ export function resolveAsset(
550550
}
551551
const assets = options[type]
552552
// check local registration variations first
553+
// 直接匹配
553554
if (hasOwn(assets, id)) return assets[id]
554555
const camelizedId = camelize(id)
556+
// 驼峰式匹配 (如 v-my-dir -> vMyDir)
555557
if (hasOwn(assets, camelizedId)) return assets[camelizedId]
556558
const PascalCaseId = capitalize(camelizedId)
559+
// 首字母大写匹配 (如 vMyDir -> VMyDir)
557560
if (hasOwn(assets, PascalCaseId)) return assets[PascalCaseId]
558561
// fallback to prototype chain
559562
const res = assets[id] || assets[camelizedId] || assets[PascalCaseId]

src/core/vdom/create-component.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ const componentVNodeHooks = {
4444
const mountedNode: any = vnode // work around flow
4545
componentVNodeHooks.prepatch(mountedNode, mountedNode)
4646
} else {
47+
// 创建的组件实例赋值给vnode.componentInstance
4748
const child = (vnode.componentInstance = createComponentInstanceForVnode(
4849
vnode,
4950
activeInstance
@@ -68,6 +69,7 @@ const componentVNodeHooks = {
6869
const { context, componentInstance } = vnode
6970
if (!componentInstance._isMounted) {
7071
componentInstance._isMounted = true
72+
// 组件插入时,调用mounted钩子
7173
callHook(componentInstance, 'mounted')
7274
}
7375
if (vnode.data.keepAlive) {
@@ -88,6 +90,7 @@ const componentVNodeHooks = {
8890
const { componentInstance } = vnode
8991
if (!componentInstance._isDestroyed) {
9092
if (!vnode.data.keepAlive) {
93+
// 组件销毁时,调用destroy钩子
9194
componentInstance.$destroy()
9295
} else {
9396
deactivateChildComponent(componentInstance, true /* direct */)
@@ -105,6 +108,7 @@ export function createComponent(
105108
children?: Array<VNode>,
106109
tag?: string
107110
): VNode | Array<VNode> | void {
111+
// 没有组件的构造函数,返回
108112
if (isUndef(Ctor)) {
109113
return
110114
}
@@ -119,6 +123,7 @@ export function createComponent(
119123
// if at this stage it's not a constructor or an async component factory,
120124
// reject.
121125
if (typeof Ctor !== 'function') {
126+
// 构造函数不是函数,警告
122127
if (__DEV__) {
123128
warn(`Invalid Component definition: ${String(Ctor)}`, context)
124129
}
@@ -158,6 +163,7 @@ export function createComponent(
158163
// functional component
159164
// @ts-expect-error
160165
if (isTrue(Ctor.options.functional)) {
166+
// 函数式组件使用createFunctionalComponent创建
161167
return createFunctionalComponent(
162168
Ctor as typeof Component,
163169
propsData,
@@ -188,11 +194,13 @@ export function createComponent(
188194
}
189195

190196
// install component management hooks onto the placeholder node
197+
// 装载组件的hook
191198
installComponentHooks(data)
192199

193200
// return a placeholder vnode
194201
// @ts-expect-error
195202
const name = getComponentName(Ctor.options) || tag
203+
// 创建虚拟节点
196204
const vnode = new VNode(
197205
// @ts-expect-error
198206
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
@@ -226,9 +234,10 @@ export function createComponentInstanceForVnode(
226234
options.render = inlineTemplate.render
227235
options.staticRenderFns = inlineTemplate.staticRenderFns
228236
}
237+
// 使用vue的构造函数创建实例,传入options
229238
return new vnode.componentOptions.Ctor(options)
230239
}
231-
240+
// 装载hooks
232241
function installComponentHooks(data: VNodeData) {
233242
const hooks = data.hook || (data.hook = {})
234243
for (let i = 0; i < hooksToMerge.length; i++) {

src/core/vdom/create-element.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,18 @@ export function _createElement(
6161
return createEmptyVNode()
6262
}
6363
// object syntax in v-bind
64+
// 更新is指定的tag
6465
if (isDef(data) && isDef(data.is)) {
6566
tag = data.is
6667
}
6768
if (!tag) {
6869
// in case of component :is set to falsy value
70+
// tag不存在,返回空节点
6971
return createEmptyVNode()
7072
}
7173
// warn against non-primitive key
7274
if (__DEV__ && isDef(data) && isDef(data.key) && !isPrimitive(data.key)) {
75+
// 不能使用对象作为key
7376
warn(
7477
'Avoid using non-primitive value as key, ' +
7578
'use string/number value instead.',
@@ -90,6 +93,7 @@ export function _createElement(
9093
let vnode, ns
9194
if (typeof tag === 'string') {
9295
let Ctor
96+
// 如果vnode有ns,svg等使用的命名空间
9397
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
9498
if (config.isReservedTag(tag)) {
9599
// platform built-in elements
@@ -104,6 +108,7 @@ export function _createElement(
104108
context
105109
)
106110
}
111+
// 如果是平台保留标签,创建对应的vnode
107112
vnode = new VNode(
108113
config.parsePlatformTagName(tag),
109114
data,
@@ -116,6 +121,7 @@ export function _createElement(
116121
(!data || !data.pre) &&
117122
isDef((Ctor = resolveAsset(context.$options, 'components', tag)))
118123
) {
124+
// 是组件则创建组件的vnode
119125
// component
120126
vnode = createComponent(Ctor, data, context, children, tag)
121127
} else {
@@ -125,6 +131,7 @@ export function _createElement(
125131
vnode = new VNode(tag, data, children, undefined, undefined, context)
126132
}
127133
} else {
134+
// tag不是字符串,使用createComponent创建
128135
// direct component options / constructor
129136
vnode = createComponent(tag as any, data, context, children)
130137
}

src/core/vdom/helpers/merge-hook.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ export function mergeVNodeHook(
2222

2323
if (isUndef(oldHook)) {
2424
// no existing hook
25+
// 使用统一的错误处理包装wrappedHook
2526
invoker = createFnInvoker([wrappedHook])
2627
} else {
2728
/* istanbul ignore if */
2829
if (isDef(oldHook.fns) && isTrue(oldHook.merged)) {
30+
// 如果之前的hook已经是包装过的,就不用再包装了,只需要把wrappedHook添加进去
2931
// already a merged invoker
3032
invoker = oldHook
3133
invoker.fns.push(wrappedHook)
@@ -34,7 +36,7 @@ export function mergeVNodeHook(
3436
invoker = createFnInvoker([oldHook, wrappedHook])
3537
}
3638
}
37-
39+
// 设置合并过的标志
3840
invoker.merged = true
3941
def[hookKey] = invoker
4042
}

0 commit comments

Comments
 (0)