# createElement的实现
下面这段文字是引用vue官网的,对render函数的一个说明,我们看一个看到有一个createElement
的参数,那这个createElement
又是怎么实现的呢
render 类型**:
(createElement: () => VNode) => VNode
详细:
字符串模板的代替方案,允许你发挥 JavaScript 最大的编程能力。该渲染函数接收一个
createElement
方法作为第一个参数用来创建VNode
。如果组件是一个函数组件,渲染函数还会接收一个额外的
context
参数,为没有实例的函数组件提供上下文信息。Vue 选项中的
render
函数若存在,则 Vue 构造函数不会从template
选项或通过el
选项指定的挂载元素中提取出的 HTML 模板编译渲染函数。
通过上一节组件更新概览我们就可以知道render函数的这个参数createElement
就是下面的vm.$createElement
vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)
1
2
2
那我们就看一下createElement
的具体实现
src/core/vdom/create-element.js
export function createElement (
context: Component, // 上下文,实际就是指当前vue的实例
tag: any, // 一个 HTML 标签名、组件选项对象,或者 resolve 了上述任何一种的一个 async 函数。必填项。
data: any, // 模板中 attribute 对应的数据对象
children: any, // 子级虚拟节点 (VNodes),由 `createElement()` 构建而成
normalizationType: any,
alwaysNormalize: boolean
): VNode | Array<VNode> {
// 如果data不是个对象的话,那么说明data就是children
if (Array.isArray(data) || isPrimitive(data)) {
normalizationType = children
children = data
data = undefined
}
if (isTrue(alwaysNormalize)) {
normalizationType = ALWAYS_NORMALIZE
}
return _createElement(context, tag, data, children, normalizationType)
}
export function _createElement (
context: Component,
tag?: string | Class<Component> | Function | Object,
data?: VNodeData,
children?: any,
normalizationType?: number
): VNode | Array<VNode> {
if (isDef(data) && isDef((data: any).__ob__)) {
return createEmptyVNode()
}
// 动态组件的判断 <component v-bind:is="currentTabComponent"></component>
if (isDef(data) && isDef(data.is)) {
tag = data.is
}
// 如果没有了就创建一个空的vnode
if (!tag) {
// in case of component :is set to falsy value
return createEmptyVNode()
}
//
if (Array.isArray(children) &&
typeof children[0] === 'function'
) {
data = data || {}
data.scopedSlots = { default: children[0] }
children.length = 0
}
if (normalizationType === ALWAYS_NORMALIZE) {
children = normalizeChildren(children)
} else if (normalizationType === SIMPLE_NORMALIZE) {
children = simpleNormalizeChildren(children)
}
let vnode, ns
// 如果标签是字符串,这里有两种情况,一种是原生的标签,一种是通过Vue.component注册的全局标签
if (typeof tag === 'string') {
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
if (config.isReservedTag(tag)) {
vnode = new VNode(
config.parsePlatformTagName(tag), data, children,
undefined, undefined, context
)
} else if ((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
// 如果是全局注册的组件,这里要从Vue.options下找到,即这里的Ctor,传入createComponent中
vnode = createComponent(Ctor, data, context, children, tag)
} else {
// 如果是原生的标签,这里直接创建VNode
vnode = new VNode(
tag, data, children,
undefined, undefined, context
)
}
} else {
// 如果是组件的话就需要先创建组件建
vnode = createComponent(tag, data, context, children)
}
if (Array.isArray(vnode)) {
return vnode
} else if (isDef(vnode)) {
if (isDef(ns)) applyNS(vnode, ns)
if (isDef(data)) registerDeepBindings(data)
return vnode
} else {
return createEmptyVNode()
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
下面是一个例子大家可以试试用一下createElement
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<style>
#container {
height: 100px;
width: 100px;
border: 1px solid red;
}
</style>
</head>
<body>
<div id="container" />
<script>
vm = new Vue({
el: '#container',
data() {
return {
title: '这是一个标题'
}
},
render(createElement) {
return createElement('h1', this.title)
}
})
</script>
</body>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34