|
@ -8,7 +8,7 @@ import VNode from './vnode' |
|
|
import { isPrimitive, warn } from '../util/index' |
|
|
import { isPrimitive, warn } from '../util/index' |
|
|
|
|
|
|
|
|
const emptyNode = VNode('', {}, []) |
|
|
const emptyNode = VNode('', {}, []) |
|
|
const hooks = ['create', 'update', 'remove', 'destroy', 'pre', 'post'] |
|
|
const hooks = ['create', 'update', 'remove', 'destroy'] |
|
|
|
|
|
|
|
|
function isUndef (s) { |
|
|
function isUndef (s) { |
|
|
return s === undefined |
|
|
return s === undefined |
|
@ -283,10 +283,64 @@ export function createPatchFunction (backend) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function invokeInsertHook (queue) { |
|
|
|
|
|
for (i = 0; i < queue.length; ++i) { |
|
|
|
|
|
queue[i].data.hook.insert(queue[i]) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function hydrate (elm, vnode, insertedVnodeQueue) { |
|
|
|
|
|
if (process.env.NODE_ENV !== 'production') { |
|
|
|
|
|
if (!assertNodeMatch(elm, vnode)) { |
|
|
|
|
|
return false |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
vnode.elm = elm |
|
|
|
|
|
const { tag, data, children } = vnode |
|
|
|
|
|
if (isDef(data)) { |
|
|
|
|
|
if (isDef(i = data.hook) && isDef(i = i.init)) i(vnode) |
|
|
|
|
|
if (isDef(i = vnode.child)) { |
|
|
|
|
|
// child component. it should have hydrated its own tree.
|
|
|
|
|
|
invokeCreateHooks(vnode, insertedVnodeQueue) |
|
|
|
|
|
return true |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (isDef(tag)) { |
|
|
|
|
|
if (isDef(children)) { |
|
|
|
|
|
const childNodes = elm.childNodes |
|
|
|
|
|
for (let i = 0; i < children.length; i++) { |
|
|
|
|
|
let success = hydrate(childNodes[i], children[i], insertedVnodeQueue) |
|
|
|
|
|
if (!success) { |
|
|
|
|
|
return false |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
if (isDef(data)) { |
|
|
|
|
|
invokeCreateHooks(vnode, insertedVnodeQueue) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
return true |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
function assertNodeMatch (node, vnode) { |
|
|
|
|
|
if (vnode.tag) { |
|
|
|
|
|
if (vnode.tag.indexOf('vue-component' === 0)) { |
|
|
|
|
|
return true |
|
|
|
|
|
} else { |
|
|
|
|
|
return vnode.tag === node.tagName.toLowerCase() && ( |
|
|
|
|
|
vnode.children |
|
|
|
|
|
? vnode.children.length === node.childNodes.length |
|
|
|
|
|
: node.childNodes.length === 0 |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
} else { |
|
|
|
|
|
return vnode.text === node.textContent |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return function patch (oldVnode, vnode) { |
|
|
return function patch (oldVnode, vnode) { |
|
|
var i, elm, parent |
|
|
var elm, parent |
|
|
var insertedVnodeQueue = [] |
|
|
var insertedVnodeQueue = [] |
|
|
for (i = 0; i < cbs.pre.length; ++i) cbs.pre[i]() |
|
|
|
|
|
|
|
|
|
|
|
if (!oldVnode) { |
|
|
if (!oldVnode) { |
|
|
// empty mount, create new root element
|
|
|
// empty mount, create new root element
|
|
@ -295,9 +349,25 @@ export function createPatchFunction (backend) { |
|
|
if (sameVnode(oldVnode, vnode)) { |
|
|
if (sameVnode(oldVnode, vnode)) { |
|
|
patchVnode(oldVnode, vnode, insertedVnodeQueue) |
|
|
patchVnode(oldVnode, vnode, insertedVnodeQueue) |
|
|
} else { |
|
|
} else { |
|
|
// mounting to a real element, just replace it
|
|
|
|
|
|
// TODO: pick up and reuse existing elements (hydration)
|
|
|
|
|
|
if (isUndef(oldVnode.tag)) { |
|
|
if (isUndef(oldVnode.tag)) { |
|
|
|
|
|
// mounting to a real element
|
|
|
|
|
|
// check if this is server-rendered content and if we can perform
|
|
|
|
|
|
// a successful hydration.
|
|
|
|
|
|
if (oldVnode.hasAttribute('server-rendered')) { |
|
|
|
|
|
oldVnode.removeAttribute('server-rendered') |
|
|
|
|
|
if (hydrate(oldVnode, vnode, insertedVnodeQueue)) { |
|
|
|
|
|
invokeInsertHook(insertedVnodeQueue) |
|
|
|
|
|
return oldVnode |
|
|
|
|
|
} else if (process.env.NODE_ENV !== 'production') { |
|
|
|
|
|
warn( |
|
|
|
|
|
'The client-side rendered virtual DOM tree is not matching ' + |
|
|
|
|
|
'server-rendered content. Bailing hydration and performing ' + |
|
|
|
|
|
'full client-side render.' |
|
|
|
|
|
) |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
// either not server-rendered, or hydration failed.
|
|
|
|
|
|
// create an empty node and replace it
|
|
|
oldVnode = emptyNodeAt(oldVnode) |
|
|
oldVnode = emptyNodeAt(oldVnode) |
|
|
} |
|
|
} |
|
|
elm = oldVnode.elm |
|
|
elm = oldVnode.elm |
|
@ -312,10 +382,7 @@ export function createPatchFunction (backend) { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (i = 0; i < insertedVnodeQueue.length; ++i) { |
|
|
invokeInsertHook(insertedVnodeQueue) |
|
|
insertedVnodeQueue[i].data.hook.insert(insertedVnodeQueue[i]) |
|
|
|
|
|
} |
|
|
|
|
|
for (i = 0; i < cbs.post.length; ++i) cbs.post[i]() |
|
|
|
|
|
return vnode.elm |
|
|
return vnode.elm |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|