functioncreateComponent (Ctor,data,context,children,tag) { if (isUndef(Ctor)) { return }
var baseCtor = context.$options._base;
// plain options object: turn it into a constructor if (isObject(Ctor)) { Ctor = baseCtor.extend(Ctor); }
// if at this stage it's not a constructor or an async component factory, // reject. if (typeofCtor !== 'function') { return }
// async component var asyncFactory; if (isUndef(Ctor.cid)) { asyncFactory = Ctor; Ctor = resolveAsyncComponent(asyncFactory, baseCtor, context); if (Ctor === undefined) { // return a placeholder node for async component, which is rendered // as a comment node but preserves all the raw information for the node. // the information will be used for async server-rendering and hydration. returncreateAsyncPlaceholder( asyncFactory, data, context, children, tag ) } }
data = data || {};
// resolve constructor options in case global mixins are applied after // component constructor creation resolveConstructorOptions(Ctor);
// transform component v-model data into props & events if (isDef(data.model)) { transformModel(Ctor.options, data); }
// extract props var propsData = extractPropsFromVNodeData(data, Ctor, tag);
// extract listeners, since these needs to be treated as // child component listeners instead of DOM listeners var listeners = data.on; // replace with listeners with .native modifier // so it gets processed during parent component patch. data.on = data.nativeOn;
if (isTrue(Ctor.options.abstract)) { // abstract components do not keep anything // other than props & listeners & slot
// work around flow var slot = data.slot; data = {}; if (slot) { data.slot = slot; } }
// install component management hooks onto the placeholder node installComponentHooks(data);
// return a placeholder vnode var name = Ctor.options.name || tag; var vnode = newVNode( ("vue-component-" + (Ctor.cid) + (name ? ("-" + name) : '')), data, undefined, undefined, undefined, context, { Ctor: Ctor, propsData: propsData, listeners: listeners, tag: tag, children: children }, asyncFactory );
Vue.prototype._update = function (vnode, hydrating) { var vm = this; var prevEl = vm.$el; var prevVnode = vm._vnode; var restoreActiveInstance = setActiveInstance(vm); vm._vnode = vnode; // Vue.prototype.__patch__ is injected in entry points // based on the rendering backend used. if (!prevVnode) { // initial render vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); } else { // updates vm.$el = vm.__patch__(prevVnode, vnode); } restoreActiveInstance(); // update __vue__ reference if (prevEl) { prevEl.__vue__ = null; } if (vm.$el) { vm.$el.__vue__ = vm; } // if parent is an HOC, update its $el as well if (vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el; } // updated hook is called by the scheduler to ensure that children are // updated in a parent's updated hook. };
function createComponent (vnode, insertedVnodeQueue, parentElm, refElm) { var i = vnode.data; if (isDef(i)) { var isReactivated = isDef(vnode.componentInstance) && i.keepAlive; if (isDef(i = i.hook) && isDef(i = i.init)) { i(vnode, false /* hydrating */); } // after calling the init hook, if the vnode is a child component // it should've created a child instance and mounted it. the child // component also has set the placeholder vnode's elm. // in that case we can just return the element and be done. // 会调用data.init.hook,会创建一个子组件的vm实例,同时会将vm实例挂载到vnode.componentInstance上 // 再通过$mount挂载,对页面进行渲染 // 最终子组件生成的DOM 可通过 vnode.componentInstance.$el 拿到 if (isDef(vnode.componentInstance)) { initComponent(vnode, insertedVnodeQueue); insert(parentElm, vnode.elm, refElm); if (isTrue(isReactivated)) { reactivateComponent(vnode, insertedVnodeQueue, parentElm, refElm); } return true } } }