8000 vue虚拟dom文档 · gitbu/learn-vue@1ebb355 · GitHub
[go: up one dir, main page]

Skip to content

Commit 1ebb355

Browse files
author
buaiping
committed
vue虚拟dom文档
1 parent 4ede70c commit 1ebb355

21 files changed

+1127
-21
lines changed

.DS_Store

0 Bytes
Binary file not shown.

demo/.DS_Store

0 Bytes
Binary file not shown.

demo/render.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
return createElement('h1', this.title)
3030
}
3131
})
32+
console.log('@@@', vm)
3233
</script>
3334

3435
</body>

docs/.vuepress/config.js

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,19 +62,41 @@ module.exports = {
6262
}, {
6363
title: '虚拟DOM',
6464
collapsable: false,
65+
children: [{
66+
title: '组件挂载更新',
67+
collapsable: true,
68+
children: [
69+
'vdom/组件挂载过程',
70+
'vdom/组件更新过程',
71+
'vdom/createElement',
72+
'vdom/createComponent',
73+
'vdom/vnode',
74+
],
75+
}, {
76+
title: 'domDiff',
77+
collapsable: true,
78+
children: [
79+
'vdom/domDiff/vnode对比流程图',
80+
'vdom/domDiff/patch',
81+
'vdom/domDiff/createElm',
82+
'vdom/domDiff/invokeCreateHooks',
83+
'vdom/domDiff/patchVnode',
84+
'vdom/domDiff/updateChildren',
85+
],
86+
}]
87+
}, {
88+
title: '全局API',
89+
collapsable: false,
6590
children: [
66-
'vdom/组件挂载过程',
67-
'vdom/组件更新过程',
68-
'vdom/createElement',
69-
'vdom/createComponent',
70-
'vdom/vnode',
71-
'vdom/domDiff',
91+
'全局API/component和filter和directive',
92+
'全局API/use',
93+
'全局API/observable',
94+
'全局API/extend',
7295
]
7396
}, {
74-
title: '全局API',
97+
title: '编译原理',
7598
collapsable: false,
7699
children: [
77-
'全局API/Vue.component'
78100
]
79101
}
80102
]
0 Bytes
Binary file not shown.

docs/.vuepress/public/assets/patch.svg

Lines changed: 2 additions & 0 deletions
Loading

docs/vue2/vdom/createComponent.md

Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,213 @@
11
# createComponent的实现过程
22

3+
```js
4+
export function createComponent (
5+
Ctor: Class<Component> | Function | Object | void,
6+
data: ?VNodeData,
7+
context: Component,
8+
children: ?Array<VNode>,
9+
tag?: string
10+
): VNode | Array<VNode> | void {
11+
if (isUndef(Ctor)) {
12+
return
13+
}
14+
// 这里的context就是Vue的实例,然后这个_base实际就是Vue
15+
const baseCtor = context.$options._base
16+
17+
// plain options object: turn it into a constructor
18+
// 这里调用extend方法就是用Vue的一个子类来代表这个组件
19+
if (isObject(Ctor)) {
20+
Ctor = baseCtor.extend(Ctor)
21+
}
22+
23+
// if at this stage it's not a constructor or an async component factory,
24+
// reject.
25+
if (typeof Ctor !== 'function') {
26+
if (process.env.NODE_ENV !== 'production') {
27+
warn(`Invalid Component definition: ${String(Ctor)}`, context)
28+
}
29+
return
30+
}
31+
32+
// async component
33+
let asyncFactory
34+
if (isUndef(Ctor.cid)) {
35+
asyncFactory = Ctor
36+
Ctor = resolveAsyncComponent(asyncFactory, baseCtor)
37+
if (Ctor === undefined) {
38+
// return a placeholder node for async component, which is rendered
39+
// as a comment node but preserves all the raw information for the node.
40+
// the information will be used for async server-rendering and hydration.
41+
return createAsyncPlaceholder(
42+
asyncFactory,
43+
data,
44+
context,
45+
children,
46+
tag
47+
)
48+
}
49+
}
50+
51+
data = data || {}
52+
53+
// resolve constructor options in case global mixins are applied after
54+
// component constructor creation
55+
resolveConstructorOptions(Ctor)
56+
57+
// transform component v-model data into props & events
58+
if (isDef(data.model)) {
59+
transformModel(Ctor.options, data)
60+
}
61+
62+
// extract props
63+
const propsData = extractPropsFromVNodeData(data, Ctor, tag)
64+
65+
// functional component
66+
// 如果是函数式组件
67+
if (isTrue(Ctor.options.functional)) {
68+
return createFunctionalComponent(Ctor, propsData, data, context, children)
69+
}
70+
71+
// extract listeners, since these needs to be treated as
72+
// child component listeners instead of DOM listeners
73+
const listeners = data.on
74+
// replace with listeners with .native modifier
75+
// so it gets processed during parent component patch.
76+
data.on = data.nativeOn
77+
78+
if (isTrue(Ctor.options.abstract)) {
79+
// abstract components do not keep anything
80+
// other than props & listeners & slot
81+
82+
// work around flow
83+
const slot = data.slot
84+
data = {}
85+
if (slot) {
86+
data.slot = slot
87+
}
88+
}
89+
90+
// install component management hooks onto the placeholder node
91+
// 安装Hook,这个在后边的patch会用到的
92+
installComponentHooks(data)
93+
94+
// return a placeholder vnode
95+
const name = Ctor.options.name || tag
96+
// 创建VNode
97+
const vnode = new VNode(
98+
`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,
99+
data, undefined, undefined, undefined, context,
100+
{ Ctor, propsData, listeners, tag, children },
101+
asyncFactory
102+
)
103+
104+
// Weex specific: invoke recycle-list optimized @render function for
105+
// extracting cell-slot template.
106+
// https://github.com/Hanks10100/weex-native-directive/tree/master/component
107+
/* istanbul ignore if */
108+
if (__WEEX__ && isRecyclableComponent(vnode)) {
109+
return renderRecyclableComponentTemplate(vnode)
110+
}
111+
112+
return vnode
113+
}
114+
```
115+
116+
117+
118+
```js
119+
// 当data中merged为true时,就是把默认的一些hook和data中的Hook合并在一块,如果相同,按顺序执行
120+
function installComponentHooks (data: VNodeData) {
121+
const hooks = data.hook || (data.hook = {})
122+
for (let i = 0; i < hooksToMerge.length; i++) {
123+
const key = hooksToMerge[i]
124+
const existing = hooks[key]
125+
const toMerge = componentVNodeHooks[key]
126+
if (existing !== toMerge && !(existing && existing._merged)) {
127+
hooks[key] = existing ? mergeHook(toMerge, existing) : toMerge
128+
}
129+
}
130+
}
131+
132+
function mergeHook (f1: any, f2: any): Function {
133+
const merged = (a, b) => {
134+
// flow complains about extra args which is why we use any
135+
f1(a, b)
136+
f2(a, b)
137+
}
138+
merged._merged = true
139+
return merged
140+
}
141+
142+
const hooksToMerge = Object.keys(componentVNodeHooks)
143+
```
144+
145+
146+
147+
```js
148+
const componentVNodeHooks = {
149+
init (vnode: VNodeWithData, hydrating: boolean): ?boolean {
150+
if (
151+
vnode.componentInstance &&
152+
!vnode.componentInstance._isDestroyed &&
153+
vnode.data.keepAlive
154+
) {
155+
// kept-alive components, treat as a patch
156+
const mountedNode: any = vnode // work around flow
157+
componentVNodeHooks.prepatch(mountedNode, mountedNode)
158+
} else {
159+
const child = vnode.componentInstance = createComponentInstanceForVnode(
160+
vnode,
161+
activeInstance
162+
)
163+
child.$mount(hydrating ? vnode.elm : undefined, hydrating)
164+
}
165+
},
166+
167+
prepatch (oldVnode: MountedComponentVNode, vnode: MountedComponentVNode) {
168+
const options = vnode.componentOptions
169+
const child = vnode.componentInstance = oldVnode.componentInstance
170+
updateChildComponent(
171+
child,
172+
options.propsData, // updated props
173+
options.listeners, // updated listeners
174+
vnode, // new parent vnode
175+
options.children // new children
176+
)
177+
},
178+
179+
insert (vnode: MountedComponentVNode) {
180+
const { context, componentInstance } = vnode
181+
if (!componentInstance._isMounted) {
182+
componentInstance._isMounted = true
183+
callHook(componentInstance, 'mounted')
184+
}
185+
if (vnode.data.keepAlive) {
186+
if (context._isMounted) {
187+
// vue-router#1212
188+
// During updates, a kept-alive component's child components may
189+
// change, so directly walking the tree here may call activated hooks
190+
// on incorrect children. Instead we push them into a queue which will
191+
// be processed after the whole patch process ended.
192+
queueActivatedComponent(componentInstance)
193+
} else {
194+
activateChildComponent(componentInstance, true /* direct */)
195+
}
196+
}
197+
},
198+
199+
destroy (vnode: MountedComponentVNode) {
200+
const { componentInstance } = vnode
201+
if (!componentInstance._isDestroyed) {
202+
if (!vnode.data.keepAlive) {
203+
componentInstance.$destroy()
204+
} else {
205+
deactivateChildComponent(componentInstance, true /* direct */)
206+
}
207+
}
208+
}
209+
}
210+
```
211+
212+
213+

docs/vue2/vdom/createElement.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ export function _createElement (
8282
children = simpleNormalizeChildren(children)
8383
}
8484
let vnode, ns
85-
// 如果是html标签元素的话直接创建vnode
85+
// 如果标签是字符串,这里有两种情况,一种是原生的标签,一种是通过Vue.component注册的全局标签
8686
if (typeof tag === 'string') {
8787
let Ctor
8888
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
@@ -92,9 +92,10 @@ export function _createElement (
9292
undefined, undefined, context
9393
)
9494
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
95-
// component
95+
// 如果是全局注册的组件,这里要从Vue.options下找到,即这里的Ctor,传入createComponent中
9696
vnode = createComponent(Ctor, data, context, children, tag)
9797
} else {
98+
// 如果是原生的标签,这里直接创建VNode
9899
vnode = new VNode(
99100
tag, data, children,
100101
undefined, undefined, context

docs/vue2/vdom/domDiff.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)
0