@@ -6,11 +6,24 @@ function createRenderer(options) {
6
6
* @param {* } container 容器
7
7
*/
8
8
function patch ( oldVnode , newVnode , container ) {
9
- // 如果 n1 不存在,意味着挂载,则调用 mountElemnet 函数完成挂载
10
- if ( ! oldVnode ) {
11
- mountElement ( newVnode , container ) ;
12
- } else {
13
- // n1 存在,意味着打补丁
9
+ // 如果 oldVnode 存在, 则对比 oldVnode 和 newVnode 的类型
10
+ if ( oldVnode && oldVnode . type !== newVnode . type ) {
11
+ // 如果新旧 vnode 的类型不同,则直接将旧 vnode 卸载
12
+ unmount ( oldVnode ) ;
13
+ oldVnode = null ;
14
+ }
15
+
16
+ // 代码运行到这里, 证明 oldVnode 和 newVnode 所描述的内容相同
17
+ const { type } = newVnode ;
18
+
19
+ if ( typeof type === 'string' ) {
20
+ // 如果 oldVnode 不存在,意味着挂载,则调用 mountElemnet 函数完成挂载
21
+ if ( ! oldVnode ) {
22
+ mountElement ( newVnode , container ) ;
23
+ } else {
24
+ patchElement ( oldVnode , newVnode ) ;
25
+ }
26
+ } else if ( typeof type === 'object' ) {
14
27
}
15
28
}
16
29
@@ -20,7 +33,11 @@ function createRenderer(options) {
20
33
// 处理子节点,,如果子节点是字符串,代表元素具有文本节点
21
34
22
35
if ( typeof vnode . children === 'string' ) {
23
- el . textContent = vnode . children ;
36
+ options . setElementText ( el , vnode . children ) ;
37
+ } else if ( Array . isArray ( vnode . children ) ) {
38
+ vnode . children . forEach ( child => {
39
+ patch ( null , child , el ) ;
40
+ } ) ;
24
41
}
25
42
26
43
// 如果 vnode.props 存在才处理下
@@ -38,19 +55,27 @@ function createRenderer(options) {
38
55
options . insert ( el , container ) ;
39
56
}
40
57
58
+ function unmount ( vnode ) {
59
+ const parent = vnode . el . parentNode ;
60
+ if ( parent ) {
61
+ // eslint-disable-next-line unicorn/prefer-dom-node-remove
62
+ parent . removeChild ( vnode . el ) ;
63
+ }
64
+ }
65
+
41
66
function render ( vnode , container ) {
42
67
if ( vnode ) {
43
68
// 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数,进行打补丁
44
- patch ( container . __vnode , vnode , container ) ;
69
+ patch ( container . _vnode , vnode , container ) ;
45
70
} else {
46
- if ( container . __vnode ) {
47
- // 旧值 存在,且新 vnode 不存在,说明是卸载(unmount)操作
48
- // 只需要将 container 内的 DOM 清空即可
49
- container . innerHTML = '' ;
71
+ // eslint-disable-next-line no-lonely-if
72
+ if ( container . _vnode ) {
73
+ // 调用 unmount 函数卸载 vnode
74
+ unmount ( container . _vnode ) ;
50
75
}
51
-
52
- container . __vnode = vnode ;
53
76
}
77
+
78
+ container . _vnode = vnode ;
54
79
}
55
80
56
81
function hydrate ( vnode , container ) { }
@@ -61,4 +86,37 @@ function createRenderer(options) {
61
86
} ;
62
87
}
63
88
64
- export { createRenderer } ;
89
+ /**
90
+ * 处理 class 样式
91
+ * @param {* } cls
92
+ * @returns
93
+ */
94
+ function normalizeClass ( cls ) {
95
+ let result = '' ;
96
+
97
+ const normalizeObj = cls => {
98
+ for ( const [ className , sign ] of Object . entries ( cls ) ) {
99
+ if ( sign ) {
100
+ result += ` ${ className } ` ;
101
+ }
102
+ }
103
+ } ;
104
+
105
+ if ( typeof cls === 'string' ) {
106
+ result = cls ;
107
+ } else if ( Array . isArray ( cls ) ) {
108
+ for ( const clsObj of cls ) {
109
+ if ( typeof clsObj === 'string' ) {
110
+ result += ` ${ clsObj } ` ;
111
+ } else if ( typeof clsObj === 'object' && clsObj !== null ) {
112
+ normalizeObj ( cls ) ;
113
+ }
114
+ }
115
+ } else {
116
+ normalizeObj ( cls ) ;
117
+ }
118
+
119
+ return result . trim ( ) ;
120
+ }
121
+
122
+ export { createRenderer , normalizeClass } ;
0 commit comments