VNode
class VNode{
...prop
constructor(tag,data,children,text,elm,context,componentOptions,asyncFactory){
...
}
get child(){
return this.componentInstance
}
}
patch
const emptyNode = new VNode('',{},{})
const hooks = ['create','activate','update','remove','destroy']
function createPatchFunction(backend){
let i,j;
const cbs = {}
const { modules, nodeOps } = backend
for(i = 0; i < hooks.length; i ++){
cbs[hooks[i]] = {}
for(j = 0; j < modules.length; j ++){
if(isDef(modules[j][hooks[i]])){
cbs[hooks[i]].push(modules[j][hooks[i]])
}
}
}
...
let hydrationBailed = false
const isRenderedModule = makeMap('attrs,class,staticClass,staticStyle,key')
return function patch(oldVnode,vnode,hydrating,removeOnly){
if(isUndef(vnode)){
if(isDef(oldVnode)) invokeDestroyHook(oldVnode)
return
}
let isInitialPatch = false
const insertedVnodeQueue = []
if(isUndef(oldVnode)){
isInitialPatch = true
createElm(vnode,insertedVnodeQueue)
}else{
const isRealElement = isDef(oldVnode.nodeType)
if(!isRealElement && sameVnode(oldVnode,vnode)){
patchVnode(oldVnode,vnode,insertedVnodeQueue,null,null,removeOnly)
}else{
if(isRealElement){
}
const oldElm = oldVnode.elm
const parentElm = nodeOps.parentNode(oldElm)
createElm(vnode,insertedVnodeQueue,oldElm._leaveCb? null : parentElm,nodeOps.nextSibling(oldElm))
if(isDef(vnode.parent)){
let ancestor = vnode.parent
const patchable = isPatchable(vnode)
while(ancestor){
for(let i = 0; i < cbs.destroy.length; ++ i){
cbs.destroy[i](ancestor)
}
ancestor.elm = vnode.elm
if(patchable){
for(let i = 0; i < cbs.create.length; ++ i){
cbs.create[i](emptyNode,ancestor)
}
const insert = ancestor.data.hook.insert
if(insert.merged){
for(let i = 1; i < insert.fns.length; i ++){
insert.fns[i]()
}
}
}else{
registerRef(ancestor)
}
ancestor = ancestor.parent
}
}
if(isDef(parentElm)){
removeVnodes([oldVnode],0,0)
}else if(isDef(oldVnode.tag)){
invokeDestroyHook(oldVnode)
}
}
}
invokeInsertHook(vnode,insertedVnodeQueue,isInitialPatch)
return vnode.elm
}
}
create-functional-component
function createFunctionalComponent(Ctor,propsData,data,contextVm,children){
const options = Ctor.options
const props = {}
const propOptions = options.props
if(isDef(propOptions)){
for(const key in propOptions){
props[key] = validateProp(key,propOptions,propsData || emptyObject)
}
}else{
if(isDef(data.attrs)) mergeProps(props,data.attrs)
if(isDef(data.props)) mergeProps(props,data.props)
}
const renderContext = new FunctionalRenderContext(data,props,children,contextVm,Ctor)
const vnode = options.render.call(null,renderContext._c,renderContext)
if(vnode instanceof VNode){
return cloneAndMarkFunctionalResult(vnode,data,renderContext.parent,options,renderContext)
}else if(Array.isArray(vnode)){
const vnodes = normalizeChildren(vnode) || []
const res = new Array(vnodes.length)
for(let i = 0; i < vnodes.length; i ++){
res[i] = cloneAndMarkFunctionalResult(vnodes[i],data,renderContext.parent,options,renderContext)
}
return res
}
}
createElement
function _createElement(context,tag,data,children,normalizationType){
if(isDef(data) && isDef(data.__ob__)){
return createEmptyVnode()
}
if(isDef(data) && isDef(data.is)){
tag = data.is
}
if(!tag){
return createEmptyVnode()
}
if(process.env.NODE_ENV !== 'production' && isDef(data) && isDef(data.key) && !isPrimitive(data.key)){
...
}
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;
if(typeof tag === 'string'){
let Ctor
ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
if(config.isReservedTag(tag)){
...
vnode = new VNode(config.parsePlatformTagName(ns),data,children,undefined,undefined,context)
}else if((!data || !data.pre) && isDef(Ctor = resolveAsset(context.$options,'components',tag))){
vnode = createComponent(Ctor,data,context,children,tag)
}else{
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()
}
}
createComponent
function createComponent(Ctor,data,context,children,tag){
const baseCtor = context.$options._base
if(isObject(Ctor)){
Ctor = baseCtor.extend(Ctor)
}
if(typeOf Ctor !== 'function'){
if(process.env.NODE_ENV !== 'production'){
warn(`Invalid Component definition:${String(Ctor)}`,context)
}
return
}
let asyncFactory
if(isUndef(Ctor.cid)){
asyncFactory = Ctor
Ctor = resolveAsyncComponent(asyncFactory,baseCtor)
if(Ctor === undefined){
return createAsyncPlaceholder(asyncFactory,data,context,children,tag)
}
}
data = data || {}
resolveConstructorOptions(Ctor)
if(isDef(data.model)){
transformModel(Ctor.options,data)
}
const propsData = extractPropsFormVnodeData(data,Ctor,tag)
if(isTrue(Ctor.options.functional)){
return createFunctionalComponent(Ctor,propsData,data,context,children)
}
const listeners = data.on
data.on = data.nativeOn
if(isTrue(Ctor.options.abstract)){
const slot = data.slot
data = {}
if(slot){
data.slot = slot
}
}
installComponentHooks(data)
const name = Ctor.options.name || tag
const vnode = new VNode(`vue-component-${Ctor.cid}${name ? `-${name}` : ''}`,data,undefined,undefined,undefined,context,{Ctor,propsData,listeners,tag,children,},asyncFactory)
if(__WEEX__ && isRecycleableComponent(vnode)){
return renderRecycleableComponentTemplate(vnode)
}
return vnode
}
transformModel --- v-model
function transformModel(options,data){
const prop = (options.model && options.model.prop) || 'value'
const event = (options.model && options.model.event) || 'input'
(data.attrs || (data.attrs = {}))[prop] = data.model.value
const on = data.on || data.on = {}
const existing = on[event]
const callback = data.model.callback
if(isDef(existing)){
if(Array.isArray(existing) ? existing.indexOf(callback) === -1 : existing !== callback){
on[event] = [callback].concat(existing)
}
}else{
on[event] = callback
}
}