1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 | import VNode, { cloneVNode } from './vnode'
|
14 | import config from '../config'
|
15 | import { SSR_ATTR } from 'shared/constants'
|
16 | import { registerRef } from './modules/ref'
|
17 | import { traverse } from '../observer/traverse'
|
18 | import { activeInstance } from '../instance/lifecycle'
|
19 | import { isTextInputType } from 'web/util/element'
|
20 |
|
21 | import {
|
22 | warn,
|
23 | isDef,
|
24 | isUndef,
|
25 | isTrue,
|
26 | makeMap,
|
27 | isRegExp,
|
28 | isPrimitive
|
29 | } from '../util/index'
|
30 |
|
31 | export const emptyNode = new VNode('', {}, [])
|
32 |
|
33 | const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
|
34 |
|
35 | function sameVnode (a, b) {
|
36 | return (
|
37 | a.key === b.key &&
|
38 | a.asyncFactory === b.asyncFactory && (
|
39 | (
|
40 | a.tag === b.tag &&
|
41 | a.isComment === b.isComment &&
|
42 | isDef(a.data) === isDef(b.data) &&
|
43 | sameInputType(a, b)
|
44 | ) || (
|
45 | isTrue(a.isAsyncPlaceholder) &&
|
46 | isUndef(b.asyncFactory.error)
|
47 | )
|
48 | )
|
49 | )
|
50 | }
|
51 |
|
52 | function sameInputType (a, b) {
|
53 | if (a.tag !== 'input') return true
|
54 | let i
|
55 | const typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type
|
56 | const typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type
|
57 | return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
|
58 | }
|
59 |
|
60 | function createKeyToOldIdx (children, beginIdx, endIdx) {
|
61 | let i, key
|
62 | const map = {}
|
63 | for (i = beginIdx; i <= endIdx; ++i) {
|
64 | key = children[i].key
|
65 | if (isDef(key)) map[key] = i
|
66 | }
|
67 | return map
|
68 | }
|
69 |
|
70 | export function createPatchFunction (backend) {
|
71 | let i, j
|
72 | const cbs = {}
|
73 |
|
74 | const { modules, nodeOps } = backend
|
75 |
|
76 | for (i = 0; i < hooks.length; ++i) {
|
77 | cbs[hooks[i]] = []
|
78 | for (j = 0; j < modules.length; ++j) {
|
79 | if (isDef(modules[j][hooks[i]])) {
|
80 | cbs[hooks[i]].push(modules[j][hooks[i]])
|
81 | }
|
82 | }
|
83 | }
|
84 |
|
85 | function emptyNodeAt (elm) {
|
86 | return new VNode(nodeOps.tagName(elm).toLowerCase(), {}, [], undefined, elm)
|
87 | }
|
88 |
|
89 | function createRmCb (childElm, listeners) {
|
90 | function remove () {
|
91 | if (--remove.listeners === 0) {
|
92 | removeNode(childElm)
|
93 | }
|
94 | }
|
95 | remove.listeners = listeners
|
96 | return remove
|
97 | }
|
98 |
|
99 | function removeNode (el) {
|
100 | const parent = nodeOps.parentNode(el)
|
101 |
|
102 | if (isDef(parent)) {
|
103 | nodeOps.removeChild(parent, el)
|
104 | }
|
105 | }
|
106 |
|
107 | function isUnknownElement (vnode, inVPre) {
|
108 | return (
|
109 | !inVPre &&
|
110 | !vnode.ns &&
|
111 | !(
|
112 | config.ignoredElements.length &&
|
113 | config.ignoredElements.some(ignore => {
|
114 | return isRegExp(ignore)
|
115 | ? ignore.test(vnode.tag)
|
116 | : ignore === vnode.tag
|
117 | })
|
118 | ) &&
|
119 | config.isUnknownElement(vnode.tag)
|
120 | )
|
121 | }
|
122 |
|
123 | let creatingElmInVPre = 0
|
124 |
|
125 | function createElm (
|
126 | vnode,
|
127 | insertedVnodeQueue,
|
128 | parentElm,
|
129 | refElm,
|
130 | nested,
|
131 | ownerArray,
|
132 | index
|
133 | ) {
|
134 | if (isDef(vnode.elm) && isDef(ownerArray)) {
|
135 |
|
136 |
|
137 |
|
138 |
|
139 |
|
140 | vnode = ownerArray[index] = cloneVNode(vnode)
|
141 | }
|
142 |
|
143 | vnode.isRootInsert = !nested
|
144 | if (createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
|
145 | return
|
146 | }
|
147 |
|
148 | const data = vnode.data
|
149 | const children = vnode.children
|
150 | const tag = vnode.tag
|
151 | if (isDef(tag)) {
|
152 | if (process.env.NODE_ENV !== 'production') {
|
153 | if (data && data.pre) {
|
154 | creatingElmInVPre++
|
155 | }
|
156 | if (isUnknownElement(vnode, creatingElmInVPre)) {
|
157 | warn(
|
158 | 'Unknown custom element: <' + tag + '> - did you ' +
|
159 | 'register the component correctly? For recursive components, ' +
|
160 | 'make sure to provide the "name" option.',
|
161 | vnode.context
|
162 | )
|
163 | }
|
164 | }
|
165 |
|
166 | vnode.elm = vnode.ns
|
167 | ? nodeOps.createElementNS(vnode.ns, tag)
|
168 | : nodeOps.createElement(tag, vnode)
|
169 | setScope(vnode)
|
170 |
|
171 |
|
172 | if (__WEEX__) {
|
173 |
|
174 |
|
175 |
|
176 | const appendAsTree = isDef(data) && isTrue(data.appendAsTree)
|
177 | if (!appendAsTree) {
|
178 | if (isDef(data)) {
|
179 | invokeCreateHooks(vnode, insertedVnodeQueue)
|
180 | }
|
181 | insert(parentElm, vnode.elm, refElm)
|
182 | }
|
183 | createChildren(vnode, children, insertedVnodeQueue)
|
184 | if (appendAsTree) {
|
185 | if (isDef(data)) {
|
186 | invokeCreateHooks(vnode, insertedVnodeQueue)
|
187 | }
|
188 | insert(parentElm, vnode.elm, refElm)
|
189 | }
|
190 | } else {
|
191 | createChildren(vnode, children, insertedVnodeQueue)
|
192 | if (isDef(data)) {
|
193 | invokeCreateHooks(vnode, insertedVnodeQueue)
|
194 | }
|
195 | insert(parentElm, vnode.elm, refElm)
|
196 | }
|
197 |
|
198 | if (process.env.NODE_ENV !== 'production' && data && data.pre) {
|
199 | creatingElmInVPre--
|
200 | }
|
201 | } else if (isTrue(vnode.isComment)) {
|
202 | vnode.elm = nodeOps.createComment(vnode.text)
|
203 | insert(parentElm, vnode.elm, refElm)
|
204 | } else {
|
205 | vnode.elm = nodeOps.createTextNode(vnode.text)
|
206 | insert(parentElm, vnode.elm, refElm)
|
207 | }
|
208 | }
|
209 |
|
210 | function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
|
211 | let i = vnode.data
|
212 | if (isDef(i)) {
|
213 | const isReactivated = isDef(vnode.componentInstance) && i.keepAlive
|
214 | if (isDef(i = i.hook) && isDef(i = i.init)) {
|
215 | i(vnode, false )
|
216 | }
|
217 |
|
218 |
|
219 |
|
220 |
|
221 | if (isDef(vnode.componentInstance)) {
|
222 | initComponent(vnode, insertedVnodeQueue)
|
223 | insert(parentElm, vnode.elm, refElm)
|
224 | if (isTrue(isReactivated)) {
|
225 | reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm)
|
226 | }
|
227 | return true
|
228 | }
|
229 | }
|
230 | }
|
231 |
|
232 | function initComponent (vnode, insertedVnodeQueue) {
|
233 | if (isDef(vnode.data.pendingInsert)) {
|
234 | insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
|
235 | vnode.data.pendingInsert = null
|
236 | }
|
237 | vnode.elm = vnode.componentInstance.$el
|
238 | if (isPatchable(vnode)) {
|
239 | invokeCreateHooks(vnode, insertedVnodeQueue)
|
240 | setScope(vnode)
|
241 | } else {
|
242 |
|
243 |
|
244 | registerRef(vnode)
|
245 |
|
246 | insertedVnodeQueue.push(vnode)
|
247 | }
|
248 | }
|
249 |
|
250 | function reactivateComponent (vnode, insertedVnodeQueue, parentElm, refElm) {
|
251 | let i
|
252 |
|
253 |
|
254 |
|
255 |
|
256 | let innerNode = vnode
|
257 | while (innerNode.componentInstance) {
|
258 | innerNode = innerNode.componentInstance._vnode
|
259 | if (isDef(i = innerNode.data) && isDef(i = i.transition)) {
|
260 | for (i = 0; i < cbs.activate.length; ++i) {
|
261 | cbs.activate[i](emptyNode, innerNode)
|
262 | }
|
263 | insertedVnodeQueue.push(innerNode)
|
264 | break
|
265 | }
|
266 | }
|
267 |
|
268 |
|
269 | insert(parentElm, vnode.elm, refElm)
|
270 | }
|
271 |
|
272 | function insert (parent, elm, ref) {
|
273 | if (isDef(parent)) {
|
274 | if (isDef(ref)) {
|
275 | if (nodeOps.parentNode(ref) === parent) {
|
276 | nodeOps.insertBefore(parent, elm, ref)
|
277 | }
|
278 | } else {
|
279 | nodeOps.appendChild(parent, elm)
|
280 | }
|
281 | }
|
282 | }
|
283 |
|
284 | function createChildren (vnode, children, insertedVnodeQueue) {
|
285 | if (Array.isArray(children)) {
|
286 | if (process.env.NODE_ENV !== 'production') {
|
287 | checkDuplicateKeys(children)
|
288 | }
|
289 | for (let i = 0; i < children.length; ++i) {
|
290 | createElm(children[i], insertedVnodeQueue, vnode.elm, null, true, children, i)
|
291 | }
|
292 | } else if (isPrimitive(vnode.text)) {
|
293 | nodeOps.appendChild(vnode.elm, nodeOps.createTextNode(String(vnode.text)))
|
294 | }
|
295 | }
|
296 |
|
297 | function isPatchable (vnode) {
|
298 | while (vnode.componentInstance) {
|
299 | vnode = vnode.componentInstance._vnode
|
300 | }
|
301 | return isDef(vnode.tag)
|
302 | }
|
303 |
|
304 | function invokeCreateHooks (vnode, insertedVnodeQueue) {
|
305 | for (let i = 0; i < cbs.create.length; ++i) {
|
306 | cbs.create[i](emptyNode, vnode)
|
307 | }
|
308 | i = vnode.data.hook
|
309 | if (isDef(i)) {
|
310 | if (isDef(i.create)) i.create(emptyNode, vnode)
|
311 | if (isDef(i.insert)) insertedVnodeQueue.push(vnode)
|
312 | }
|
313 | }
|
314 |
|
315 |
|
316 |
|
317 |
|
318 | function setScope (vnode) {
|
319 | let i
|
320 | if (isDef(i = vnode.fnScopeId)) {
|
321 | nodeOps.setStyleScope(vnode.elm, i)
|
322 | } else {
|
323 | let ancestor = vnode
|
324 | while (ancestor) {
|
325 | if (isDef(i = ancestor.context) && isDef(i = i.$options._scopeId)) {
|
326 | nodeOps.setStyleScope(vnode.elm, i)
|
327 | }
|
328 | ancestor = ancestor.parent
|
329 | }
|
330 | }
|
331 |
|
332 | if (isDef(i = activeInstance) &&
|
333 | i !== vnode.context &&
|
334 | i !== vnode.fnContext &&
|
335 | isDef(i = i.$options._scopeId)
|
336 | ) {
|
337 | nodeOps.setStyleScope(vnode.elm, i)
|
338 | }
|
339 | }
|
340 |
|
341 | function addVnodes (parentElm, refElm, vnodes, startIdx, endIdx, insertedVnodeQueue) {
|
342 | for (; startIdx <= endIdx; ++startIdx) {
|
343 | createElm(vnodes[startIdx], insertedVnodeQueue, parentElm, refElm, false, vnodes, startIdx)
|
344 | }
|
345 | }
|
346 |
|
347 | function invokeDestroyHook (vnode) {
|
348 | let i, j
|
349 | const data = vnode.data
|
350 | if (isDef(data)) {
|
351 | if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode)
|
352 | for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode)
|
353 | }
|
354 | if (isDef(i = vnode.children)) {
|
355 | for (j = 0; j < vnode.children.length; ++j) {
|
356 | invokeDestroyHook(vnode.children[j])
|
357 | }
|
358 | }
|
359 | }
|
360 |
|
361 | function removeVnodes (vnodes, startIdx, endIdx) {
|
362 | for (; startIdx <= endIdx; ++startIdx) {
|
363 | const ch = vnodes[startIdx]
|
364 | if (isDef(ch)) {
|
365 | if (isDef(ch.tag)) {
|
366 | removeAndInvokeRemoveHook(ch)
|
367 | invokeDestroyHook(ch)
|
368 | } else {
|
369 | removeNode(ch.elm)
|
370 | }
|
371 | }
|
372 | }
|
373 | }
|
374 |
|
375 | function removeAndInvokeRemoveHook (vnode, rm) {
|
376 | if (isDef(rm) || isDef(vnode.data)) {
|
377 | let i
|
378 | const listeners = cbs.remove.length + 1
|
379 | if (isDef(rm)) {
|
380 |
|
381 |
|
382 | rm.listeners += listeners
|
383 | } else {
|
384 |
|
385 | rm = createRmCb(vnode.elm, listeners)
|
386 | }
|
387 |
|
388 | if (isDef(i = vnode.componentInstance) && isDef(i = i._vnode) && isDef(i.data)) {
|
389 | removeAndInvokeRemoveHook(i, rm)
|
390 | }
|
391 | for (i = 0; i < cbs.remove.length; ++i) {
|
392 | cbs.remove[i](vnode, rm)
|
393 | }
|
394 | if (isDef(i = vnode.data.hook) && isDef(i = i.remove)) {
|
395 | i(vnode, rm)
|
396 | } else {
|
397 | rm()
|
398 | }
|
399 | } else {
|
400 | removeNode(vnode.elm)
|
401 | }
|
402 | }
|
403 |
|
404 | function updateChildren (parentElm, oldCh, newCh, insertedVnodeQueue, removeOnly) {
|
405 | let oldStartIdx = 0
|
406 | let newStartIdx = 0
|
407 | let oldEndIdx = oldCh.length - 1
|
408 | let oldStartVnode = oldCh[0]
|
409 | let oldEndVnode = oldCh[oldEndIdx]
|
410 | let newEndIdx = newCh.length - 1
|
411 | let newStartVnode = newCh[0]
|
412 | let newEndVnode = newCh[newEndIdx]
|
413 | let oldKeyToIdx, idxInOld, vnodeToMove, refElm
|
414 |
|
415 |
|
416 |
|
417 |
|
418 | const canMove = !removeOnly
|
419 |
|
420 | if (process.env.NODE_ENV !== 'production') {
|
421 | checkDuplicateKeys(newCh)
|
422 | }
|
423 |
|
424 | while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
|
425 | if (isUndef(oldStartVnode)) {
|
426 | oldStartVnode = oldCh[++oldStartIdx]
|
427 | } else if (isUndef(oldEndVnode)) {
|
428 | oldEndVnode = oldCh[--oldEndIdx]
|
429 | } else if (sameVnode(oldStartVnode, newStartVnode)) {
|
430 | patchVnode(oldStartVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
|
431 | oldStartVnode = oldCh[++oldStartIdx]
|
432 | newStartVnode = newCh[++newStartIdx]
|
433 | } else if (sameVnode(oldEndVnode, newEndVnode)) {
|
434 | patchVnode(oldEndVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
|
435 | oldEndVnode = oldCh[--oldEndIdx]
|
436 | newEndVnode = newCh[--newEndIdx]
|
437 | } else if (sameVnode(oldStartVnode, newEndVnode)) {
|
438 | patchVnode(oldStartVnode, newEndVnode, insertedVnodeQueue, newCh, newEndIdx)
|
439 | canMove && nodeOps.insertBefore(parentElm, oldStartVnode.elm, nodeOps.nextSibling(oldEndVnode.elm))
|
440 | oldStartVnode = oldCh[++oldStartIdx]
|
441 | newEndVnode = newCh[--newEndIdx]
|
442 | } else if (sameVnode(oldEndVnode, newStartVnode)) {
|
443 | patchVnode(oldEndVnode, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
|
444 | canMove && nodeOps.insertBefore(parentElm, oldEndVnode.elm, oldStartVnode.elm)
|
445 | oldEndVnode = oldCh[--oldEndIdx]
|
446 | newStartVnode = newCh[++newStartIdx]
|
447 | } else {
|
448 | if (isUndef(oldKeyToIdx)) oldKeyToIdx = createKeyToOldIdx(oldCh, oldStartIdx, oldEndIdx)
|
449 | idxInOld = isDef(newStartVnode.key)
|
450 | ? oldKeyToIdx[newStartVnode.key]
|
451 | : findIdxInOld(newStartVnode, oldCh, oldStartIdx, oldEndIdx)
|
452 | if (isUndef(idxInOld)) {
|
453 | createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
|
454 | } else {
|
455 | vnodeToMove = oldCh[idxInOld]
|
456 | if (sameVnode(vnodeToMove, newStartVnode)) {
|
457 | patchVnode(vnodeToMove, newStartVnode, insertedVnodeQueue, newCh, newStartIdx)
|
458 | oldCh[idxInOld] = undefined
|
459 | canMove && nodeOps.insertBefore(parentElm, vnodeToMove.elm, oldStartVnode.elm)
|
460 | } else {
|
461 |
|
462 | createElm(newStartVnode, insertedVnodeQueue, parentElm, oldStartVnode.elm, false, newCh, newStartIdx)
|
463 | }
|
464 | }
|
465 | newStartVnode = newCh[++newStartIdx]
|
466 | }
|
467 | }
|
468 | if (oldStartIdx > oldEndIdx) {
|
469 | refElm = isUndef(newCh[newEndIdx + 1]) ? null : newCh[newEndIdx + 1].elm
|
470 | addVnodes(parentElm, refElm, newCh, newStartIdx, newEndIdx, insertedVnodeQueue)
|
471 | } else if (newStartIdx > newEndIdx) {
|
472 | removeVnodes(oldCh, oldStartIdx, oldEndIdx)
|
473 | }
|
474 | }
|
475 |
|
476 | function checkDuplicateKeys (children) {
|
477 | const seenKeys = {}
|
478 | for (let i = 0; i < children.length; i++) {
|
479 | const vnode = children[i]
|
480 | const key = vnode.key
|
481 | if (isDef(key)) {
|
482 | if (seenKeys[key]) {
|
483 | warn(
|
484 | `Duplicate keys detected: '${key}'. This may cause an update error.`,
|
485 | vnode.context
|
486 | )
|
487 | } else {
|
488 | seenKeys[key] = true
|
489 | }
|
490 | }
|
491 | }
|
492 | }
|
493 |
|
494 | function findIdxInOld (node, oldCh, start, end) {
|
495 | for (let i = start; i < end; i++) {
|
496 | const c = oldCh[i]
|
497 | if (isDef(c) && sameVnode(node, c)) return i
|
498 | }
|
499 | }
|
500 |
|
501 | function patchVnode (
|
502 | oldVnode,
|
503 | vnode,
|
504 | insertedVnodeQueue,
|
505 | ownerArray,
|
506 | index,
|
507 | removeOnly
|
508 | ) {
|
509 | if (oldVnode === vnode) {
|
510 | return
|
511 | }
|
512 |
|
513 | if (isDef(vnode.elm) && isDef(ownerArray)) {
|
514 |
|
515 | vnode = ownerArray[index] = cloneVNode(vnode)
|
516 | }
|
517 |
|
518 | const elm = vnode.elm = oldVnode.elm
|
519 |
|
520 | if (isTrue(oldVnode.isAsyncPlaceholder)) {
|
521 | if (isDef(vnode.asyncFactory.resolved)) {
|
522 | hydrate(oldVnode.elm, vnode, insertedVnodeQueue)
|
523 | } else {
|
524 | vnode.isAsyncPlaceholder = true
|
525 | }
|
526 | return
|
527 | }
|
528 |
|
529 |
|
530 |
|
531 |
|
532 |
|
533 | if (isTrue(vnode.isStatic) &&
|
534 | isTrue(oldVnode.isStatic) &&
|
535 | vnode.key === oldVnode.key &&
|
536 | (isTrue(vnode.isCloned) || isTrue(vnode.isOnce))
|
537 | ) {
|
538 | vnode.componentInstance = oldVnode.componentInstance
|
539 | return
|
540 | }
|
541 |
|
542 | let i
|
543 | const data = vnode.data
|
544 | if (isDef(data) && isDef(i = data.hook) && isDef(i = i.prepatch)) {
|
545 | i(oldVnode, vnode)
|
546 | }
|
547 |
|
548 | const oldCh = oldVnode.children
|
549 | const ch = vnode.children
|
550 | if (isDef(data) && isPatchable(vnode)) {
|
551 | for (i = 0; i < cbs.update.length; ++i) cbs.update[i](oldVnode, vnode)
|
552 | if (isDef(i = data.hook) && isDef(i = i.update)) i(oldVnode, vnode)
|
553 | }
|
554 | if (isUndef(vnode.text)) {
|
555 | if (isDef(oldCh) && isDef(ch)) {
|
556 | if (oldCh !== ch) updateChildren(elm, oldCh, ch, insertedVnodeQueue, removeOnly)
|
557 | } else if (isDef(ch)) {
|
558 | if (process.env.NODE_ENV !== 'production') {
|
559 | checkDuplicateKeys(ch)
|
560 | }
|
561 | if (isDef(oldVnode.text)) nodeOps.setTextContent(elm, '')
|
562 | addVnodes(elm, null, ch, 0, ch.length - 1, insertedVnodeQueue)
|
563 | } else if (isDef(oldCh)) {
|
564 | removeVnodes(oldCh, 0, oldCh.length - 1)
|
565 | } else if (isDef(oldVnode.text)) {
|
566 | nodeOps.setTextContent(elm, '')
|
567 | }
|
568 | } else if (oldVnode.text !== vnode.text) {
|
569 | nodeOps.setTextContent(elm, vnode.text)
|
570 | }
|
571 | if (isDef(data)) {
|
572 | if (isDef(i = data.hook) && isDef(i = i.postpatch)) i(oldVnode, vnode)
|
573 | }
|
574 | }
|
575 |
|
576 | function invokeInsertHook (vnode, queue, initial) {
|
577 |
|
578 |
|
579 | if (isTrue(initial) && isDef(vnode.parent)) {
|
580 | vnode.parent.data.pendingInsert = queue
|
581 | } else {
|
582 | for (let i = 0; i < queue.length; ++i) {
|
583 | queue[i].data.hook.insert(queue[i])
|
584 | }
|
585 | }
|
586 | }
|
587 |
|
588 | let hydrationBailed = false
|
589 |
|
590 |
|
591 |
|
592 |
|
593 | const isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key')
|
594 |
|
595 |
|
596 | function hydrate (elm, vnode, insertedVnodeQueue, inVPre) {
|
597 | let i
|
598 | const { tag, data, children } = vnode
|
599 | inVPre = inVPre || (data && data.pre)
|
600 | vnode.elm = elm
|
601 |
|
602 | if (isTrue(vnode.isComment) && isDef(vnode.asyncFactory)) {
|
603 | vnode.isAsyncPlaceholder = true
|
604 | return true
|
605 | }
|
606 |
|
607 | if (process.env.NODE_ENV !== 'production') {
|
608 | if (!assertNodeMatch(elm, vnode, inVPre)) {
|
609 | return false
|
610 | }
|
611 | }
|
612 | if (isDef(data)) {
|
613 | if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode, true )
|
614 | if (isDef(i = vnode.componentInstance)) {
|
615 |
|
616 | initComponent(vnode, insertedVnodeQueue)
|
617 | return true
|
618 | }
|
619 | }
|
620 | if (isDef(tag)) {
|
621 | if (isDef(children)) {
|
622 |
|
623 | if (!elm.hasChildNodes()) {
|
624 | createChildren(vnode, children, insertedVnodeQueue)
|
625 | } else {
|
626 |
|
627 | if (isDef(i = data) && isDef(i = i.domProps) && isDef(i = i.innerHTML)) {
|
628 | if (i !== elm.innerHTML) {
|
629 |
|
630 | if (process.env.NODE_ENV !== 'production' &&
|
631 | typeof console !== 'undefined' &&
|
632 | !hydrationBailed
|
633 | ) {
|
634 | hydrationBailed = true
|
635 | console.warn('Parent: ', elm)
|
636 | console.warn('server innerHTML: ', i)
|
637 | console.warn('client innerHTML: ', elm.innerHTML)
|
638 | }
|
639 | return false
|
640 | }
|
641 | } else {
|
642 |
|
643 | let childrenMatch = true
|
644 | let childNode = elm.firstChild
|
645 | for (let i = 0; i < children.length; i++) {
|
646 | if (!childNode || !hydrate(childNode, children[i], insertedVnodeQueue, inVPre)) {
|
647 | childrenMatch = false
|
648 | break
|
649 | }
|
650 | childNode = childNode.nextSibling
|
651 | }
|
652 |
|
653 |
|
654 | if (!childrenMatch || childNode) {
|
655 |
|
656 | if (process.env.NODE_ENV !== 'production' &&
|
657 | typeof console !== 'undefined' &&
|
658 | !hydrationBailed
|
659 | ) {
|
660 | hydrationBailed = true
|
661 | console.warn('Parent: ', elm)
|
662 | console.warn('Mismatching childNodes vs. VNodes: ', elm.childNodes, children)
|
663 | }
|
664 | return false
|
665 | }
|
666 | }
|
667 | }
|
668 | }
|
669 | if (isDef(data)) {
|
670 | let fullInvoke = false
|
671 | for (const key in data) {
|
672 | if (!isRenderedModule(key)) {
|
673 | fullInvoke = true
|
674 | invokeCreateHooks(vnode, insertedVnodeQueue)
|
675 | break
|
676 | }
|
677 | }
|
678 | if (!fullInvoke && data['class']) {
|
679 |
|
680 | traverse(data['class'])
|
681 | }
|
682 | }
|
683 | } else if (elm.data !== vnode.text) {
|
684 | elm.data = vnode.text
|
685 | }
|
686 | return true
|
687 | }
|
688 |
|
689 | function assertNodeMatch (node, vnode, inVPre) {
|
690 | if (isDef(vnode.tag)) {
|
691 | return vnode.tag.indexOf('vue-component') === 0 || (
|
692 | !isUnknownElement(vnode, inVPre) &&
|
693 | vnode.tag.toLowerCase() === (node.tagName && node.tagName.toLowerCase())
|
694 | )
|
695 | } else {
|
696 | return node.nodeType === (vnode.isComment ? 8 : 3)
|
697 | }
|
698 | }
|
699 |
|
700 | return function patch (oldVnode, vnode, hydrating, removeOnly) {
|
701 | if (isUndef(vnode)) {
|
702 | if (isDef(oldVnode)) invokeDestroyHook(oldVnode)
|
703 | return
|
704 | }
|
705 |
|
706 | let isInitialPatch = false
|
707 | const insertedVnodeQueue = []
|
708 |
|
709 | if (isUndef(oldVnode)) {
|
710 |
|
711 | isInitialPatch = true
|
712 | createElm(vnode, insertedVnodeQueue)
|
713 | } else {
|
714 | const isRealElement = isDef(oldVnode.nodeType)
|
715 | if (!isRealElement && sameVnode(oldVnode, vnode)) {
|
716 |
|
717 | patchVnode(oldVnode, vnode, insertedVnodeQueue, null, null, removeOnly)
|
718 | } else {
|
719 | if (isRealElement) {
|
720 |
|
721 |
|
722 |
|
723 | if (oldVnode.nodeType === 1 && oldVnode.hasAttribute(SSR_ATTR)) {
|
724 | oldVnode.removeAttribute(SSR_ATTR)
|
725 | hydrating = true
|
726 | }
|
727 | if (isTrue(hydrating)) {
|
728 | if (hydrate(oldVnode, vnode, insertedVnodeQueue)) {
|
729 | invokeInsertHook(vnode, insertedVnodeQueue, true)
|
730 | return oldVnode
|
731 | } else if (process.env.NODE_ENV !== 'production') {
|
732 | warn(
|
733 | 'The client-side rendered virtual DOM tree is not matching ' +
|
734 | 'server-rendered content. This is likely caused by incorrect ' +
|
735 | 'HTML markup, for example nesting block-level elements inside ' +
|
736 | '<p>, or missing <tbody>. Bailing hydration and performing ' +
|
737 | 'full client-side render.'
|
738 | )
|
739 | }
|
740 | }
|
741 |
|
742 |
|
743 | oldVnode = emptyNodeAt(oldVnode)
|
744 | }
|
745 |
|
746 |
|
747 | const oldElm = oldVnode.elm
|
748 | const parentElm = nodeOps.parentNode(oldElm)
|
749 |
|
750 |
|
751 | createElm(
|
752 | vnode,
|
753 | insertedVnodeQueue,
|
754 |
|
755 |
|
756 |
|
757 | oldElm._leaveCb ? null : parentElm,
|
758 | nodeOps.nextSibling(oldElm)
|
759 | )
|
760 |
|
761 |
|
762 | if (isDef(vnode.parent)) {
|
763 | let ancestor = vnode.parent
|
764 | const patchable = isPatchable(vnode)
|
765 | while (ancestor) {
|
766 | for (let i = 0; i < cbs.destroy.length; ++i) {
|
767 | cbs.destroy[i](ancestor)
|
768 | }
|
769 | ancestor.elm = vnode.elm
|
770 | if (patchable) {
|
771 | for (let i = 0; i < cbs.create.length; ++i) {
|
772 | cbs.create[i](emptyNode, ancestor)
|
773 | }
|
774 |
|
775 |
|
776 |
|
777 | const insert = ancestor.data.hook.insert
|
778 | if (insert.merged) {
|
779 |
|
780 | for (let i = 1; i < insert.fns.length; i++) {
|
781 | insert.fns[i]()
|
782 | }
|
783 | }
|
784 | } else {
|
785 | registerRef(ancestor)
|
786 | }
|
787 | ancestor = ancestor.parent
|
788 | }
|
789 | }
|
790 |
|
791 |
|
792 | if (isDef(parentElm)) {
|
793 | removeVnodes([oldVnode], 0, 0)
|
794 | } else if (isDef(oldVnode.tag)) {
|
795 | invokeDestroyHook(oldVnode)
|
796 | }
|
797 | }
|
798 | }
|
799 |
|
800 | invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
|
801 | return vnode.elm
|
802 | }
|
803 | }
|