1 | import { diff, unmount, applyRef } from './index';
|
2 | import { createVNode, Fragment } from '../create-element';
|
3 | import { EMPTY_OBJ, EMPTY_ARR } from '../constants';
|
4 | import { getDomSibling } from '../component';
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | export function diffChildren(
|
27 | parentDom,
|
28 | renderResult,
|
29 | newParentVNode,
|
30 | oldParentVNode,
|
31 | globalContext,
|
32 | isSvg,
|
33 | excessDomChildren,
|
34 | commitQueue,
|
35 | oldDom,
|
36 | isHydrating
|
37 | ) {
|
38 | let i, j, oldVNode, childVNode, newDom, firstChildDom, refs;
|
39 |
|
40 |
|
41 |
|
42 | let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
|
43 |
|
44 | let oldChildrenLength = oldChildren.length;
|
45 |
|
46 | newParentVNode._children = [];
|
47 | for (i = 0; i < renderResult.length; i++) {
|
48 | childVNode = renderResult[i];
|
49 |
|
50 | if (childVNode == null || typeof childVNode == 'boolean') {
|
51 | childVNode = newParentVNode._children[i] = null;
|
52 | }
|
53 |
|
54 |
|
55 |
|
56 | else if (
|
57 | typeof childVNode == 'string' ||
|
58 | typeof childVNode == 'number' ||
|
59 |
|
60 | typeof childVNode == 'bigint'
|
61 | ) {
|
62 | childVNode = newParentVNode._children[i] = createVNode(
|
63 | null,
|
64 | childVNode,
|
65 | null,
|
66 | null,
|
67 | childVNode
|
68 | );
|
69 | } else if (Array.isArray(childVNode)) {
|
70 | childVNode = newParentVNode._children[i] = createVNode(
|
71 | Fragment,
|
72 | { children: childVNode },
|
73 | null,
|
74 | null,
|
75 | null
|
76 | );
|
77 | } else if (childVNode._depth > 0) {
|
78 |
|
79 |
|
80 |
|
81 |
|
82 | childVNode = newParentVNode._children[i] = createVNode(
|
83 | childVNode.type,
|
84 | childVNode.props,
|
85 | childVNode.key,
|
86 | childVNode.ref ? childVNode.ref : null,
|
87 | childVNode._original
|
88 | );
|
89 | } else {
|
90 | childVNode = newParentVNode._children[i] = childVNode;
|
91 | }
|
92 |
|
93 |
|
94 |
|
95 | if (childVNode == null) {
|
96 | continue;
|
97 | }
|
98 |
|
99 | childVNode._parent = newParentVNode;
|
100 | childVNode._depth = newParentVNode._depth + 1;
|
101 |
|
102 |
|
103 |
|
104 |
|
105 |
|
106 | oldVNode = oldChildren[i];
|
107 |
|
108 | if (
|
109 | oldVNode === null ||
|
110 | (oldVNode &&
|
111 | childVNode.key == oldVNode.key &&
|
112 | childVNode.type === oldVNode.type)
|
113 | ) {
|
114 | oldChildren[i] = undefined;
|
115 | } else {
|
116 |
|
117 |
|
118 | for (j = 0; j < oldChildrenLength; j++) {
|
119 | oldVNode = oldChildren[j];
|
120 |
|
121 |
|
122 | if (
|
123 | oldVNode &&
|
124 | childVNode.key == oldVNode.key &&
|
125 | childVNode.type === oldVNode.type
|
126 | ) {
|
127 | oldChildren[j] = undefined;
|
128 | break;
|
129 | }
|
130 | oldVNode = null;
|
131 | }
|
132 | }
|
133 |
|
134 | oldVNode = oldVNode || EMPTY_OBJ;
|
135 |
|
136 |
|
137 | diff(
|
138 | parentDom,
|
139 | childVNode,
|
140 | oldVNode,
|
141 | globalContext,
|
142 | isSvg,
|
143 | excessDomChildren,
|
144 | commitQueue,
|
145 | oldDom,
|
146 | isHydrating
|
147 | );
|
148 |
|
149 | newDom = childVNode._dom;
|
150 |
|
151 | if ((j = childVNode.ref) && oldVNode.ref != j) {
|
152 | if (!refs) refs = [];
|
153 | if (oldVNode.ref) refs.push(oldVNode.ref, null, childVNode);
|
154 | refs.push(j, childVNode._component || newDom, childVNode);
|
155 | }
|
156 |
|
157 | if (newDom != null) {
|
158 | if (firstChildDom == null) {
|
159 | firstChildDom = newDom;
|
160 | }
|
161 |
|
162 | if (
|
163 | typeof childVNode.type == 'function' &&
|
164 | childVNode._children === oldVNode._children
|
165 | ) {
|
166 | childVNode._nextDom = oldDom = reorderChildren(
|
167 | childVNode,
|
168 | oldDom,
|
169 | parentDom
|
170 | );
|
171 | } else {
|
172 | oldDom = placeChild(
|
173 | parentDom,
|
174 | childVNode,
|
175 | oldVNode,
|
176 | oldChildren,
|
177 | newDom,
|
178 | oldDom
|
179 | );
|
180 | }
|
181 |
|
182 | if (typeof newParentVNode.type == 'function') {
|
183 |
|
184 |
|
185 |
|
186 |
|
187 |
|
188 |
|
189 |
|
190 | newParentVNode._nextDom = oldDom;
|
191 | }
|
192 | } else if (
|
193 | oldDom &&
|
194 | oldVNode._dom == oldDom &&
|
195 | oldDom.parentNode != parentDom
|
196 | ) {
|
197 |
|
198 |
|
199 | oldDom = getDomSibling(oldVNode);
|
200 | }
|
201 | }
|
202 |
|
203 | newParentVNode._dom = firstChildDom;
|
204 |
|
205 |
|
206 | for (i = oldChildrenLength; i--; ) {
|
207 | if (oldChildren[i] != null) {
|
208 | unmount(oldChildren[i], oldChildren[i]);
|
209 | }
|
210 | }
|
211 |
|
212 |
|
213 | if (refs) {
|
214 | for (i = 0; i < refs.length; i++) {
|
215 | applyRef(refs[i], refs[++i], refs[++i]);
|
216 | }
|
217 | }
|
218 | }
|
219 |
|
220 | function reorderChildren(childVNode, oldDom, parentDom) {
|
221 |
|
222 | let c = childVNode._children;
|
223 | let tmp = 0;
|
224 | for (; c && tmp < c.length; tmp++) {
|
225 | let vnode = c[tmp];
|
226 | if (vnode) {
|
227 |
|
228 |
|
229 |
|
230 |
|
231 | vnode._parent = childVNode;
|
232 |
|
233 | if (typeof vnode.type == 'function') {
|
234 | oldDom = reorderChildren(vnode, oldDom, parentDom);
|
235 | } else {
|
236 | oldDom = placeChild(parentDom, vnode, vnode, c, vnode._dom, oldDom);
|
237 | }
|
238 | }
|
239 | }
|
240 |
|
241 | return oldDom;
|
242 | }
|
243 |
|
244 |
|
245 |
|
246 |
|
247 |
|
248 |
|
249 |
|
250 | export function toChildArray(children, out) {
|
251 | out = out || [];
|
252 | if (children == null || typeof children == 'boolean') {
|
253 | } else if (Array.isArray(children)) {
|
254 | children.some(child => {
|
255 | toChildArray(child, out);
|
256 | });
|
257 | } else {
|
258 | out.push(children);
|
259 | }
|
260 | return out;
|
261 | }
|
262 |
|
263 | function placeChild(
|
264 | parentDom,
|
265 | childVNode,
|
266 | oldVNode,
|
267 | oldChildren,
|
268 | newDom,
|
269 | oldDom
|
270 | ) {
|
271 | let nextDom;
|
272 | if (childVNode._nextDom !== undefined) {
|
273 |
|
274 |
|
275 |
|
276 | nextDom = childVNode._nextDom;
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 | childVNode._nextDom = undefined;
|
283 | } else if (
|
284 | oldVNode == null ||
|
285 | newDom != oldDom ||
|
286 | newDom.parentNode == null
|
287 | ) {
|
288 | outer: if (oldDom == null || oldDom.parentNode !== parentDom) {
|
289 | parentDom.appendChild(newDom);
|
290 | nextDom = null;
|
291 | } else {
|
292 |
|
293 | for (
|
294 | let sibDom = oldDom, j = 0;
|
295 | (sibDom = sibDom.nextSibling) && j < oldChildren.length;
|
296 | j += 1
|
297 | ) {
|
298 | if (sibDom == newDom) {
|
299 | break outer;
|
300 | }
|
301 | }
|
302 | parentDom.insertBefore(newDom, oldDom);
|
303 | nextDom = oldDom;
|
304 | }
|
305 | }
|
306 |
|
307 |
|
308 |
|
309 |
|
310 | if (nextDom !== undefined) {
|
311 | oldDom = nextDom;
|
312 | } else {
|
313 | oldDom = newDom.nextSibling;
|
314 | }
|
315 |
|
316 | return oldDom;
|
317 | }
|