componentization

Another core idea of Vue is componentization. The page is divided into multiple components, and each component has its own Template, JS, and CSS. Components can be reused and nested between components.

Use the following code as an example to analyze a Vue component initialization process.

createComponent

  1. Where to begin



  1. src/core/vdom/create-component.js

CreateComponent has three core processes: construct subclass constructors to install component hook functions and instantiate vNodes

  1. Construct the subclass constructor
  • Take a look at the definition of the vue. extend function, in SRC /core/global-api/extend.js

Vue.extend creates a subclass of Vue. It converts a pure object to a constructor Sub that inherits from Vue and returns it in a classic prototype-inheritance fashion, and then extends some properties to the Sub object itself. Such as extending options, adding global static methods, etc. The functions of props and computed are initialized. Finally, the Sub constructor is cached to avoid repeated construction of the same child component when executing vue.extend multiple times.

  1. Install component hook functions


InstallComponentHooks integrates componentVNodeHooks into data.hook and executes the hook functions when VNode executes patch. The specific implementation will be mentioned later in the patch process. During the merge process, if the hook ata certain time already exists in data.hook, then execute the mergeHook function to do the merge. The logic is simple, that is, at the final execution, execute the two hook functions one by one.

  1. Instantiation VNode


Instantiate a VNode with new VNode and return. This is different from the vnode of ordinary element node. The Vnode of component has no children, which is very critical and will be mentioned again in the patch process later.

  1. conclusion

CreateComponent has three key points when rendering a component: constructing subclass constructors, installing component hook functions, and instantiating vNode. After createComponent returns the component vNode, which is the same. The next step is to execute the vm._update method, which then executes the patch function. We briefly analyzed the patch function in the previous section, so let’s further analyze it.

patch

Execute vm. Patch to convert the VNode to a real DOM node. This process was covered in the previous section, but for a normal VNode, let’s look at how vNodes of components differ.

  1. src/core/vdom/patch.js

You can judge the createComponent (vnode insertedVnodeQueue, parentElm, refElm) return values.

  1. createComponent

The result is the init hook function, which was included in the merge hook function when we created the component VNode.

  1. src/core/vdom/create-component.js

Init hook function without considering the keepAlive first, it is through the createComponentInstanceForVnode create a Vue instance, and then call $mount subcomponents mount method.

  1. createComponentInstanceForVnode

_parentVnode for component vnode also called placeholder vnode, createComponentInstanceForVnode function to construct a parameter options, And then execute the new vnode.com ponentOptions. Ctor (options). Here vnode.com ponentOptions. Ctor corresponding is the child component constructor, the above analysis it is actually the inheritance in a constructor of Vue Sub, equivalent to a new Sub (options) here are a few parameters, _isComponent true means it is a component, and parent means the currently active component instance. So the instantiation of the child component actually happens at this point, and it executes the instance’s _init method.

  1. src/core/instance/init.js

Extract the main code


First, the options merge process has changed. _isComponent is true, so it goes to the initInternalComponent process.

InitLifecycle (VM) establishes the parent-child relationship here

The last code executed by the _init function

  1. src/core/instance/render.js

We know that after executing vm._render to generate the VNode, the next step is to execute vm._update to render the VNode.

  1. src/core/instance/lifecycle.js


  1. Back to _update, the last thing is to call patch rendering VNode. Previously analyzed in Patch, the function responsible for rendering VNode into DOM is createElm


  • The vNode we pass in is the rendered vnode of the component, which is the vm._vnode we said earlier. If the root node of the group is a normal element, then vM._vnode is also a normal vnode. Here the createComponent (vnode, insertedVnodeQueue parentElm, refElm) of the return value is false. The next step is to create a placeholder for the parent node, and then iterate over all the child vnodes recursively to createElm. If you encounter a VNode whose child VNode is a component, repeat this step. In this way, the entire tree of components can be constructed in a recursive manner.

  • Then there is the logic in createComponent to insert the entire component DOM into the parent node.

  • Insert (parentElm, vnode.elm, refElm)

  • Path.js finally deletes the old node

conclusion

Conclusion 1: If child components are created during the patch process of the component, the DOM insertion order is child before parent; component execution order is first parent before child; rendering order is child before parent. Conclusion two: One watcher per component.

This passage through the road map, the head really split, the process is very painful, through the immediately comfortable, first through a process and then really to interrupt more points to see to know how to close the loop. Can’t think out of the brain logic can’t keep up with more hands, not a big deal to write in plain English, write write on the pass.

<div id="app">

<h1> Componentization </h1>

    <div>{{name}}</div>

    <demo></demo>

</div>



When the patch

createElm(

   vnode,

   insertedVnodeQueue,

   oldElm._leaveCb ? null : parentElm,

   nodeOps.nextSibling(oldElm)

)

ParentElm is Body



The createComponent returnfalse tag = div

vnode.elm = nodeOps.createElement(tag, vnode) = div



Then the createChildren traversal div child node executes createElm passing vNode.elm =div



1.First cycle

The createComponent returnfalse tag = h1

vnode.elm = nodeOps.createElement(tag, vnode) = h1

Then createChildren traverses the h1 child node executing createElm passing vNode.elm =h1

The createComponent returnfalse tag = undefined

perform

vnode.elm = nodeOps.createTextNode(vnode.text) = test

 insertParentElm =h1 parentElm=h1 (parentElm, vnode.elm, refElm

The first cycle is over

createChildren(vnode, children, insertedVnodeQueue)

insert(parentElm, vnode.elm, refElm



2.Second cycle

The createComponent returnfalse tag = undefinded

perform

vnode.elm = nodeOps.createTextNode(vnode.text) = test

 insertParentElm =div (parentElm, vnode.elm, refElm



3.Third cycle

The createComponent returnfalse tag = div

vnode.elm = nodeOps.createElement(tag, vnode) = div

Then the createChildren traversal div child node executes createElm passing vnode.elm=div as the parent node to use

The createComponent returnfalse tag = undefined

perform

vnode.elm = nodeOps.createTextNode(vnode.text) = test

 insertParentElm =div (parentElm, vnode.elm, refElm

The third cycle ends

createChildren(vnode, children, insertedVnodeQueue)

insertParentElm =div (parentElm, vnode.elm, refElm



4.Fourth cycle

The createComponent returnfalse tag = undefinded

perform

vnode.elm = nodeOps.createTextNode(vnode.text) = test

 insertParentElm =div (parentElm, vnode.elm, refElm



5.Fifth cycle

The createComponent returntrue 

CreateComponent has two methods

1: Run I (vnode,false/* hydrating */) create a virtual DOM by executing the constructor vm._update(vm._render)

ParentElm =div. After executing one, perform two

2:insertParentElm =div (parentElm, vnode.elm, refElm



Then close the big loop

createChildren(vnode, children, insertedVnodeQueue)

insertParentElm =body (parentElm, vnode.elm, refElm



Then patch finishes logical deletion

removeVnodes([oldVnode], 0.0)

Copy the code