Commit ID: 3401f6b460196ce254a73df05ce571802b365054
先从依赖关系最少的看起来,逐步看完这个第一份提交记录的内容。所以对应的版本才到3.0.0-alpha.1
,阅读代码的时候有很多没有被使用的地方。
RuntimeDom
这个应该是vue的入口。
nodeOps
定义了一些常用的节点操作,例如创建元素、文本,追加、插入、删除元素,父、邻节点查找,Selector。
teardownVNode
定义了vNode
的销毁操作,使用handleDelegatedEvent
。handleDelegatedEvent
最后一个参数给null
,可以去除相关的事件监听, 其只负责处理如下事件。
|
|
顺着handleDelegatedEvent
阅读下去,如果同名的事件监听数量为1,移除过程就从document
中移除这个代理事件监听(removeGlobalHandler
),为0则在创建全局的事件代理(attachGlobalHandler
)。同时代码也表明el
元素下有属性__events
存着事件的处理函数,如果不存在则全局同名事件数量加一。
|
|
这段代码是全局注册代理事件的地方,此处的currentTarget
设置为document
和我平时使用这些事件的第一感觉不一样,原来是在下面的dispatchEvent
函数里面重新设置为元素自己targetRef.el = el
;
|
|
除被全局监听的事件外,需要元素自己监听的事件交给handleNormalEvent
处理,主要在patchData
中使用。
patchData
的逻辑很简单,传递当前元素、被修改的属性key、更改前后的值、更改前后的VNode
、是否是SVG、未卸载的子元素,依据key
值的不同,分别执行patchClass
, patchStyle
, patchEvent
(以on开头的属性), patchDOMProp
(以domProps开头的属性), 其余的执行patchAttr
。
patchClass
:normalizeClass(value)
后将结果给元素(就是平时传递class中使用数组或者对象或者字符串的处理逻辑),不一样的地方是svg调用setAttribute("class", ..)
,DOM元素调用.className
1。patchStyle
: 和class差不多普通化的逻辑,列表的处理逻辑是取出里面的元素,扁平化到一个对象。patchDOMProp
: 当key是innerHTML
或者textContent
且有子元素的时候,卸载子元素,更改修改前VNode的ChildrenFlags
。然后直接修改元素值。patchAttr
: 判断SVG特殊处理xLink
,其余设置属性、移除属性即可。
到此为止runtime-dom
部分的代码已经全部结束。
Scheduler
这部分代码是全部代码中最简短的部分。
queueJob
将判断当前是否在执行任务队列,是立即执行该任务,不是入队列。然后将任务回调也放入队列,判断是否在执行任务队列,不是则调用执行任务队列。
其中借助Promise.resolve()
实现nextTick
,参考MDN上的文章:深入:微任务与Javascript运行时环境
Observer
实现ref、compute等功能的基础.
工具类
全局锁,提供lock和unlock函数,目前来看作用只在core/componentProps/updateProps
中使用,让Props变为临时的可变属性。
LOCKED
#TODO
operations.ts
定义了操作类型,主要是对应Debugger事件。
state.ts
记录了Vue中对象到依赖的关系(target -> key -> dep
),raw和observed、raw和immutable之间的关系,以及被标记为不可变或者无响应式的对象集合。
在看autorun部分代码的时候,第一次看比较疑惑createAutorun
的实现(把Autorun
和autorun
看迷糊了!!),之后查找的computed.ts
代码的时候才注意到index.ts
中有autorun
的实现,在调用createAutorun
的时候已经被还原为函数:
|
|
createObservable
当中使用void 0
判断是否为空的时候,表示不解,请参考博文:为什么用「void 0」代替「undefined」; 主要是判断当前是否已经是代理对象或者已经有代理对象,如果有则返回代理对象。如果没有则判断是否可以生成Observe对象,生成新的代理对象。对Set, Map, WeakMap, WeakSet
使用collectionHandlers
; 结束的时候还添加了一下Observable对象的到key到Dep的关系表。
|
|
@startuml
abstract ComputedGetter {
-value
-dirty
+(): any
+stop: () => void
}
interface Autorun {
+(): any
+isAutorun: true
+active: boolean
+raw: Function
+deps: Array<Dep>
+scheduler?: Scheduler
+onTrack?: Debugger
+onTrigger?: Debugger
}
interface DebuggerEvent {
runner: Autorun
target: any
type: OperationTypes
key: string | symbol | undefined
}
class funtion {
createAutorun()
stop()
cleanUp()
}
class computed {
dirty: boolean = true
value: any = undefined
runner()
}
ComputedGetter::value -> Autorun
computed::runner -> funtion::createAutorun
Autorun::onTrigger --> DebuggerEvent
Autorun::onTrack --> DebuggerEvent
Autorun::raw --> funtion::createAutorun
funtion::createAutorun ..> Autorun
@enduml
baseHandler && collectionHandler
trigger && tracker
get
属性会对应到trigger
,set
属性会对应到tracker
Core
工具类
|
|
创建一个空对象,此处使用Object.freeze({})
创建对象,之后改成Object.create(null)
.
|
|
判断当前属性是否是保留的属性,包括key
、ref
、slots
之类的Vue自身的关键字,在之后的解析Props中被使用(参见: componentProps.ts
,createRender.ts
),一般都是用来跳过保留属性.
目前errorHandling.ts
在项目中没有被使用,定义了ErrorTypes(生命周期、渲染、原生事件、组件事件)和handleError的函数。
参考
SVG的className是SVGAnimatedString,而不是DOM元素的string! ↩︎