preface
Before we begin:
-
The main purpose of this article is to understand the general principle of Mounted.
-
The Vue version used is 2.6.11, and a simple demo created by VUE-CLI is an example to help you understand
-
Ignore for the moment features including but not limited to slot, functional components, server-side rendering, and other features that don’t affect understanding
-
The code posted is not exactly the same as the source code, there will be some changes and cuts as long as there are no errors (I think this helps to understand)
-
I’m not going to explain the code line by line, and it’s okay to leave out the parts that aren’t mentioned (if it’s really not careless)
Then, the sample code used for this article is as follows:
main.js
import Vue from 'vue'
import App from './App'
new Vue({
render: h= > h(App)
}).mount('#app')
Copy the code
App.vue
<template>
<div>
<div>hello, {{ msg }}</div>
<home></home>
</div>
</template>
<script>
import home from './home'
export default {
name: 'App',
components: { home },
data() {
return {
msg: 'app'
}
}
}
</script>
Copy the code
home.vue
<template>
<div>
<div>hello, {{ msg }}</div>
<div>
home component
</div>
</div>
</template>
<script>
export default {
name: 'Home',
data() {
return {
msg: 'home'
}
}
}
</script>
Copy the code
New Vue({render: H => h(App)}). Mount (‘# App ‘) to the page to display the corresponding DOM content. Vue and the attributes of the VM instance created by it, render of vNode and VM instance, initial patch and VueComponent.
Vue and vm
We know that all *. Vue files are ultimately represented at application runtime as a VM instance that has a common root VM, the former created by New VueComponent, the latter created by New Vue, VueComponent in turn inherits from Vue, so since all view-related content is dependent on Vue and VM, we need to know what properties (and methods) they have and how those properties are assigned:
The constructorVue
/ / 1
function Vue(options) {
this._init(options)
}
/ / 2
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifeCycleMixin(Vue)
renderMixin(Vue)
/ / 3
initGlobalAPI(VUe)
/ / 4
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
Object.defineProperty(Vue.prototype, '$ssrContext', {
get: function get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
});
Vue.version = '2.6.11'
// 5 install platform specific utilsVue.config.mustUseProp = mustUseProp Vue.config.isReservedTag = isReservedTag Vue.config.isReservedAttr = isReservedAttr Vue.config.getTagNamespace = getTagNamespace Vue.config.isUnknownElement = isUnknownElement// 6 install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)
// install platform patch function
Vue.prototype.__patch__ = inBrowser ? patch : noop
// public mount method
Vue.prototype.$mount = function (el, hydrating) {
el = el && inBrowser ? query(el) : undefined
return mountComponent(this, el, hydrating)
}
Copy the code
As the name implies, the purpose of those xxxmixins is to add XXX related properties to vue. prototype:
- InitMixin:
Vue.prototype
add_init
Method, this method is in thenew Vue
和new VueComponent
When executed - StateMixin:
Vue.prototype
add$set
,$delete
,$watch
methods - EventMixin:
Vue.prototype
add$on
,$once
,$emit
,$off
methods - LifeCycleMixin:
Vue.prototype
add$forceUpdate
,$destroy
,_update
methods - RenderMixin:
Vue.prototype
add_render
,$nextTick
And other Runtime convenience helpers (these method names are made up of an underscore and a single letter, called by<template>
Compile andrender
All of these methods are used in
InitGlobalAPI adds attributes to Vue:
- Config and util: not usually used
- Options: Including components, directives, filters, and _base, where the _base value is generally
Vue
Itself, for inheritance - Set, DELETE, Observable, nextTick: These attributes are different from those of
Vue.prototype
Corresponding to the related attributes of - Use, mixin: Used to add plugins and mixins
- Extend: VueComponent is generated
- Component, directive, filter: used for
Vue.options
Add attributes to the corresponding properties, such as registering a component, directive, and filter
After initGlobalApI(Vue) is executed, Vue.options.components only contains builtInComponents (only a KeepAlive), PlatformComponent (Transition and TransitionGroup) was added. Vue. Options. Directive contains both model and show directives.
The __patch__ and $mount methods are two of the most important, the latter used to start mounting an instance, and the former used to generate the DOM by comparing old and new VNodes.
That’s all the stereotype and static attributes we got from import Vue from ‘Vue’.
vm
New Vue({render: h => h(App)}), _init({render: h => h(App)}) :
Vue.prototype._init = function _init(options) {
const vm = this
vm._uid = $uid++
vm._isVue = true
// vuecomponent._init the next line of code will be different
vm.$options = mergeOptions(Vue.options, options, vm) / / 1
vm._renderProxy = vm
vm._self = vm
/ / 2
initLifeCycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, 'beforeCreate')
initInjections(vm)
initState(vm)
initProvide(vm)
callHook(vm, 'created')
if(options.el) {
vm.$mount(options.el)
}
}
Copy the code
_uid is the unique identifier of each VM and increases from 0. The root component is 0.
The mergeOptions function merges the first parameter and the attributes contained in the second parameter __ (remember there is such a thing) into a new option stored in the vm.$options property or in the VM itself (such as state), depending on the __ merge strategy When we access those attributes on the VM, we get the final merged value.
Those initxxx are used to add XXX related attributes to the VM:
- InitLifeCycle:
- $parent and $root: the initial values of the parent and root components of the current VM are correct
- $chidren, $refs: the former is used to save the child components mounted under the current VM, initialized as an empty array; The latter saves the refs owned by the current component, initialized to
{}
- _watcher, _inactive: The former is used to save the render- Wacher instance of the current VM (render-watcher is a type of watcher instance, each VM has only one) initialized to
null
; The latter is used toKeepAlive
Component, initialized tonull
- _directInactive, _isMounted, _isDestroyed, _isBeingDestroyed: The first attribute is also used
KeepAlive
Component, initialized tofalse
; All other attributes are initialized tofalse
- InitEvents:
- _events: Used to hold events bound to the current component, initialized to
Object.create(null)
- _hasHookEvent: Flags whether the event of the current component contains a name similar to
hook:created
Such an event is initialized tofalse
- _events: Used to hold events bound to the current component, initialized to
- InitRender:
- _vnode: used for saving
vm.render()
Is initialized tonull
- $vNode: Called component vNode or placeholder vnode, the current component is in its parent component
_vnode
In the form of the final call itselfrender()
Generated aftervm._vnode
Is initialized in its parent component_vnode
Represents the component VNode value. The root component can be inferred$vnode
Value is empty. - _c and $createElement: both used to generate vNode instances, the former used inside the render function compiled from the Template template, and the latter exposed as handwriting
render(h) { return h('div', 'hello') }
The first argument to the function, for examplemain.jsIn the{ render: h => h(App) }
- _staticTrees $slots $Listeners
- _vnode: used for saving
- InitInjections: processing
vm.$options.inject
,vm.k
Equivalent accessvm.options.inject.k
- InitState:
- Initialize the
vm._watchers
为[]
Is used to save all watcher instances created under the current VM, including render-Watcher, lazy-watcher (generated when handling computed data), and general Watcher - To deal with
vm.$options
In props, methods, data, and computed, their attributes can also be used directly invm
Be accessed on - To deal with
vm.$options.watcher
Create watcher instances for each of the things being watched
- Initialize the
- InitProvide: processing
vm.$options.provide
To generate thevm._provide
Is used as the inject of sub-components
The callHook executes the lifecycle hook in vm.$options and triggers the corresponding hook event if the current vm._hasHookEvent is true.
This is the process of creating a VM, followed by executing vm.$mount($el).
Render of vNode and VM instances
Before explaining what a vnode is and where it comes from, take a look at the $mount code:
Vue.prototype.$mount = function(el) {
return mountComponent(this, el)
}
function mountComponent(vm, el) {
vm.$el = el
callHook(vm, 'beforeMount')
const updateComponent = () = > vm._update(vm._render())
new Watcher(vm, updateComponent, () = > {}, {
before: () = > {
if(vm._isMounted && ! vm._isDestroyed) { callHook(vm,'beforeUpdate')}}},true /* true to render-watcher */)
if(vm.$vnode == null) {
vm._isMounted = true
callHook(vm, 'mounted')}}Copy the code
You can see that the mountComponent function does this:
- for
vm.$el
The assignment callHook(vm, 'beforeMount')
- Generate a render- Watcher instance for the current VM: Forget the detailed process and internal mechanics of generating render- Watcher, just remember that it is generated when it is executed
updateComponent
Function, which in turn will be executedvm._render()
和vm._update(vnode)
- check
vm._$vnode == null
If yes, the call is manually invokedcallHook(vm, 'mounted')
As mentioned earlier, there are usually only root componentsvm.$vnode
Is empty, so this fourth step is only for the root component$mount
Will walk to)
It is these four steps that render all the components into the DOM. As you can imagine, some action in step 3 triggers the render of the child component, which then triggers the render of the child component in step 3 until all the leaf components are rendered. Here is a brief introduction to VNode.
VNode
A VNode is a simplification of a real node in the DOM. Compared to a node with a bunch of attributes created by document.createElement, a vNode only needs the necessary attributes: tag name, attribute set, child node list, and text value to correspond to a node. In Vue, vnode is created by the constructor vnode:
class VNode {
constructor(tag, data, children, text, elm, context, componentOptions) {
this.tag = tag
// ...
this.componentOptions = componentOptions
this.componentInstance = undefined}}Copy the code
These parameters generate a vNode (of course, the vNode instance has a few other attributes, but we’ll focus on those for now) that is called a generic vnode when the tag is empty or corresponds to the tag name in the DOM, otherwise it is called a component vNode. Each component VNode corresponds to a VM. Data is used to store various properties associated with real Nodes: class, style, bound native events, etc. Just like real nodes have child nodes, children are used to store child VNodes; Text corresponds to a text node; Elm points to the node generated by the current VNode; Context refers to the VM instance where the current VNode resides. The componentOptions component is proprietary to vNode, which is used to store some data used to generate child components. ComponentInstance is also a component vNode. When a component VNode is about to be converted to a Node, a VM instance corresponding to the component VNode is generated, and then componentInstance points to the instance.
With a basic understanding of vNodes, let’s take a look at when vNodes are generated and how they are converted into real nodes.
Render of the VM instance
Render – Watcher is created using vm._render(). The _render method was added to the prototype object when renderMixin(Vue) was created. $options.render. Call (vm, vm.$createElement). The effect of this statement is to set vm as this. Vm. $options.render is passed as an argument to vm.$options.render, which is vm.$createElement(App) for the root component.
vm.$createElement = function (a, b, c) {
return _createElement(vm, a, b, c)
}
function _createElement(context, tag, data, children) {
// Context is vm, tag is App when the root component is created
if(! tag) {return createEmptyVNode()
}
let vnode
if(typeof tag === 'string') {
let Ctor
// with the same name as the HTML native tag
if(config.isReservedTag(tag)) {
vnode = new VNode(
config.parsePlatformTagName(tag), data, children,
undefined.undefined, context
)
// For a custom component, check the Context.code.components.ponents property to see if the component is registered
// The child component's render takes this step
} else if(Ctor = resolveAsset(context.$options, 'components', tag))) {
vnode = createComponent(Ctor, data, context, children, tag)
}
// Tag is the corresponding options of the component, such as App, and the render of the root component takes this step
} else {
vnode = createComponent(tag, data, context, children)
}
return vnode || createEmptyVNode()
}
Copy the code
When the tag is HTML native, call new VNode directly to generate a normal VNode return. When tag is a custom component name, the options of the custom component are resolved from the parent VM instance’s $Options.com ponents and then the createComponent is called for it and the return value is assigned to vNode. Other cases treat tag as options for a component directly. New Vue({components: {App}, render: {components: {App}, render: H => h(‘App’)}), so I added the last logic that treats the options corresponding to the component as a tag, saving a dozen characters in the main.js file.
So the next thing we need to look at is createComponent1 (there is also a function called createComponent in the source code, with a number added to avoid confusion) :
function createComponent1(Ctor, data, context, children, tag) {
if(isUndef(Ctor)) {
return
}
// The baseCtor is usually Vue
var baseCtor = context.$options._base
if (isObject(Ctor)) {
Ctor = baseCtor.extend(Ctor);
}
data = data || {}
var propsData = extractPropsFromVNodeData(data, Ctor, tag)
var listeners = data.on
data.on = data.nativeOn
// resolve constructor options in case global mixins are applied after
// component constructor creation
resolveConstructorOptions(Ctor)
// Add its own hooks for the component vNode
installComponentHooks(data)
var name = Ctor.options.name || tag
return new VNode(
('vue-component-' + (Ctor.cid) + (name ? (The '-' + name) : ' ')),
data, undefined.undefined.undefined, context,
{ Ctor, propsData, listeners, tag, children }
)
}
Copy the code
In addition to the first parameter tag name, data is also handled by installComponentHooks. In addition, there is a parameter componentOptions that general VNode does not have. It is these differences that make the patch process of VM, Each component vNode is processed to create the corresponding VueComponent constructor (componentOptions.ctor) from which the corresponding VM instance is generated. The generated VM performs its own _init, _render, _update to generate the next subinstance… Repeat until all components of the VNode are handled as they should be.
Initial patch of a component and generation of sub-components
The patch of a component refers to the process in which the corresponding Vnode of a component is converted into a real node and inserted into its parent node. Because each component instance has a component VNode instance corresponding to one of the components, the patches of the following components and vnodes refer to the same thing.
After receiving the vNode instance returned by vm.render(), the VM instance starts to patch. This process is performed at the instance level by vm._update and vm.__patch__ to convert the vNode into a real node. We know that the general VNode can be directly transformed into a real Vnode by the relevant API in DOM. How is the component VNode handled during the patch process?
The first patch
Vue.prototype._update = function(vnode) {
const vm = this
const prevEl= vm.$el
const restoreActiveInstance = setActiveInstance(vm)
vm._vnode = vnode
$el is used as oldVnode and is passed to vm.__patch__
// vm.$el is document.getelementById ('App') when vm is the root instance, null when not the root component
vm.$el = vm.__patch__(vm.$el, vnode)
restoreActiveInstance()
if (prevEl) {
prevEl.__vue__ = null;
}
if (vm.$el) {
vm.$el.__vue__ = vm;
}
}
Vue.prototype.__patch__ = function(oldVnode, vnode) {
const insertedVnodeQueue = []
let isInitialPatch = false
if(isUndef(oldVnode)) {
// 1. The first patch of the non-root component
isInitialPatch = true
createElm(vnode, insertedVnodeQueue)
} else if(isDef(oldVnode.nodeType)) {
New Vue({render: h => h(App)}).$mount('App')
oldVnode = emptyNodeAt(oldVnode)
const oldElm = oldVnode.elm
const parentElm = nodeOps.parentNode(oldElm)
createElm(vnode, insertedVnodeQueue, parentElm, nodeOps.nextSibling(oldElm))
}
invokeInsertHook(vnode, insertedVnodeQueue, isInitialPatch)
return vnode.elm
}
Copy the code
The first patch function is createElm, and the key code is as follows:
function createElm(vnode, insertedVnodeQueue, parentElm, refElm) {
// 3. Check whether it is a component VNode. If yes, exit the current function and the component vNode generates the corresponding VueComponent to generate the corresponding VM
// This is done inside createComponent, which is the aforementioned createComponent2
if(createComponent(vnode, insertedVnodeQueue, parentElm, refElm)) {
return
}
const data = vnode.data
const children = vnode.children
const tag = vnode.tag
CreateElm is recursively called on each child vNode when createChildren executes
if(isDef(tag)) {
// 4. Tag is a valid HTML tag, and createElement is a DOM node that calls document.createElement
vnode.elm = nodeOps.createElement(tag, vnode)
createChildren(vnode, children, insertedVnodeQueue)
if (isDef(data)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
}
// Insert inserts the DOM node where it should be, within its parent element
insert(parentElm, vnode.elm, refElm)
} else if(isTrue(vnode.isComment)) {
// 5. Annotate the node, insert directly
vnode.elm = nodeOps.createComment(vnode.text)
insert(parentElm, vnode.elm, refElm)
} else {
// 6. Text node, direct insert
vnode.elm = nodeOps.createTextNode(vnode.text)
insert(parentElm, vnode.elm, refElm)
}
}
Copy the code
CreateElm handles different types of VNodes as described above. The responsibility for handling the component VNode is done by createComponent2, and it is here that the child component begins its life cycle.
Generation of child components
function createComponent2(vnode, insertedVnodeQueue, parentElm, refElm) {
let i = vnode.data
if(isDef(i) && isDef(i = i.hook) && isDef(i = i.init)) {
i(vnode)
}
if(isDef(vnode.componentInstance)) {
initComponent(vnode, insertedVnodeQueue)
insert(parentElm, vnode.elm, refElm)
return true}}Copy the code
We know that the vnode.componentInstance attribute is empty when the vnode instance is created, so it must be assigned during vnode.data.hook.init(vnode). CreateComponent1 has installComponentHooks(Data), which adds proprietary hooks for each component vNode. Which includes init (which contains hooks prepatch, insert, destroy) :
const componentVNodeHooks = {
init(vnode) {
const child = vnode.componentInstance = createComponentInstanceForVnode(
vnode,
ActiveInstance is the parent component instance of child
activeInstance
)
child.$mount()
}
/ /... Other hooks
}
function createComponentInstanceForVnode(vnode, parent) {
const options = {
_isComponent: true._parentVnode: vnode,
parent: parent
}
return new vnode.componentOptions.Ctor(options)
}
Copy the code
The result of the init hook is to actually generate a VM instance for the component vNode and assign it to the vnode.ponentInstance attribute Vnode vnode) or components, and then implement vm. $mount, generate examples of work by vnode.com ponentOptions. Ctor (options), and the Ctor is child component constructor, VueComponent, which was generated in createComponent1 earlier by vue.extend (options) (the options are the objects that each single-file component is processed by vue-loader) :
Vue.exntend = function(extendOptions = {}) {
const Super = this
const superId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[superId]) {
return cachedCtors[superId]
}
const name = extendOptions.name || Super.options.name
const Sub = function VueComponent(options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(Super.options, extendOptions)
Sub['super'] = Super
if (Sub.options.props) {
initProps$1(Sub)
}
if (Sub.options.computed) {
initComputed$1(Sub)
}
Sub.extend = Super.extend
Sub.mixin = Super.mixin
Sub.use = Super.use
Vue.component. directive, vue.filter
ASSET_TYPES.forEach(function (type) {
Sub[type] = Super[type]
})
if (name) {
Sub.options.components[name] = Sub
}
Sub.superOptions = Super.options
Sub.extendOptions = extendOptions
Sub.sealedOptions = extend({}, Sub.options)
cachedCtors[SuperId] = Sub
return Sub
}
// the JSON format string corresponding to App options, the two null because the original value is a function
{
"name": "App"."components": {
"home": {
"name": "Home"."staticRenderFns": []."_compiled": true."beforeCreate": [null]."beforeDestroy": [null]."__file": "src/home.vue"}},"staticRenderFns": []."_compiled": true."beforeCreate": []."beforeDestroy": []."__file": "src/App.vue"
}
Copy the code
VueComponent, the component’s constructor, inherits the Vue constructor directly, but does not fully match it in its static properties:
-
Fewer than the latter: config, util, set, delete, nextTick, Observable, FunctionalRenderContext
-
More than the latter: super, superOptions, extendOptions, sealedOptions
-
With changes: options
Instead of the options of new Vue(Options) being used directly to generate the VM instance, the options of the component are used first to generate the corresponding Vuecomponent constructor. The options of the component are passed to vue. extend as extendOptions and vue. options are treated by mergeOptions as a new option assigned to the vuecomponent. options property. This helps reduce duplication because there is only one root component (no need to do this) and the same child component can be instantiated in multiple places, so you can store a VueComponent in extendOptions.ctor when it is first generated, corresponding to its Super CID. This saves a lot of effort each super.extend session as long as Super stays the same. VueComponent inherits VueComponent directly from Vue as long as the options of a component do not explicitly override _base. This means that vuecomponent.options. _Ctor for each child component has only one property with a value of 0 and vuue.
InitComputed $1 and initProps$1 initialize all properties in the computed object of the child component to the getter/setter of VueComponent. Prototype, and proxy all properties in the props to VueComponent. Prototype _props
This is how Vuecomponent is generated. With the constructor, the instantiation of the child component is basically the same as that of the root component, which calls this._init(options) through each lifecycle of the component VM. Also, take a look at what render looks like generated by vue-loader:
ƒ () {
var _vm = this
var _h = _vm.$createElement
var _c = _vm._self._c || _h
return _c(
"div",
[_c("div", [_vm._v("hello, " + _vm._s(_vm.msg))]), _c("home")].1)}Copy the code
RenderMixin/renderMixin/renderMixin/renderMixin/renderMixin/renderMixin
New Vue({render: h => h(App)}).$mount(‘App’) to DOM for all vm instances
- The root component VM0 patch is processed by
App
Generated component VNode - An instance of VM1 is generated for this component, VNode. Vm1 is initialized and mounted
- Repeat step 2 if you meet other component Vnodes during vm1 patch. Otherwise, it will be treated as a general Vnode (children dealing with general Vnodes may contain component Vnodes).
- Repeat step2 and step3 until all vnodes have been converted into DOM nodes and inserted into their rightful positions
/ / Mount a DOM node to its parent DOM node. / / Mount a DOM node to its parent DOM node. / / Mount a DOM node to its parent DOM node. Finally, see how the real node generated by each component vNode is inserted into the parent node, and how the corresponding VM instance triggers the Mounted hook in order.
Mounted hooks are triggered on all components
At the end of the patch method, each component vNode fires invokeInsertHook at the end of the patch:
function invokeInsertHook(vnode, queue, isInitialPatch) {
if(isTrue(isInitialPatch) && isDef(vnode.parent)) {
// Vnode. parent is a component vnode. When the VM is first patched, the corresponding component vnode will change the current value
// The queue for all vNodes whose patches have been completed is stored in data.pendingInsert.
// The vnode itself will be pushed to its parent vNode.data.pendingInsert during subsequent initComponent phases.
vnode.parent.data.pendingInsert = queue
} else {
// When invokeInsertHook is executed within the patch of the root component, the invokeInsertHook is the component vNode of all sequential patches.
// Execute their insert hooks in sequence, that is, execute the mounted hooks of the VMS corresponding to those component vNodes
for(let i = 0; i< queue.length; ++i) {
// Mounted hook
queue[i].data.hook.insert(queue[i])
}
}
}
function initComponent(vnode, insertedVnodeQueue) {
// The EL corresponding to the vnode has been generated
if(vnode.data.pendingInsert) {
/ / update the insertedVnodeQueue
insertedVnodeQueue.push.apply(insertedVnodeQueue, vnode.data.pendingInsert)
vnode.data.pendingInsert = null
}
vnode.elm = vnode.componentInstance.$el
if(isPatchable(vnode)) {
invokeCreateHooks(vnode, insertedVnodeQueue)
} else {
registerRef(vnode)
insertedVnodeQueue.push(vnode)
}
}
function invokeCreateHooks (vnode, insertedVnodeQueue) {
for (var i$1 = 0; i$1 < cbs.create.length; ++i$1) {
cbs.create[i$1](emptyNode, vnode);
}
i = vnode.data.hook; // Reuse variable
if (isDef(i)) {
if (isDef(i.create)) { i.create(emptyNode, vnode); }
if (isDef(i.insert)) { insertedVnodeQueue.push(vnode); }
}
}
componentVNodeHooks.insert = function insert(vnode) {
const componentInstance = vnode.componentInstance
if(! componentInstance._isMounted) { componentInstance._isMounted =true
callHook(componentInstance, 'mounted')}}Copy the code
Patch creates a ELM for vNode, and this elm is inserted into its parent element. So executing invokeInsertHook after createElm inside the Patch function is a good time.
InvokeInsertHook (vnode, Queue, isInitialPatch) actually does two things, when vnode is a child component vnode and is the first patch, Save the patched component vNode queue (queue) on vnode.data.peningInsert, otherwise all component VNodes are patched into real nodes and inserted into their parent node. Insert Hook(callHook(componentInstance, ‘Mounted ‘)) for vNodes in the queue.
PendingInsert for each component vnode, vnode.data.pendingInsert stores the current vnode patch, which contains the queue of subcomponent VNodes that have been patched. This is then pushed by invokeCreateHooks into the parent component vNode’s pendingInsert, Finally, all vNodes are pushed into the insertedVnodeQueue variable created when the root component’s patches are pushed in their patch order. Obviously, a component leaf vNode’s data.pendingInsert is [].
Starting from App, all component VNodes start patch successively according to the depth-first traversal principle, but the parent component is not considered to be patch completed until all the child components are completed by patch. Finally, all component VNodes form an orderly queue. Is stored in the insertedVnodeQueue that the root component started patch with. Mount Component ($mount) {/ / mount component ($mount) {/ / mount component ($mount) {/ / mount component ($mount) {/ / mount component ($mount) {/ / mount component ($mount) {/ / mount component ($mount); The mounted hook of the root component is raised at the end of this function.