What is component mount?

Component mount is the process of mounting a Vue instance to a real DOM element, which replaces the mounted real DOM when the Vue instance is parsed into a virtual DOM (node/tree) and rendered. This is called component mount. Such as:

The process of mounting components

In Vue, we typically create Vue instances like this

new Vue({
    el: '#app'.template: `<div>I am a Vue Component</div>`
})
Copy the code

Or:

new Vue({
    template: `<div>I am a Vue Component</div>`
}).$mount('#app')
Copy the code
  • In the first way, we provide an EL attribute, which indicates the actual DOM we want to mount. If we provide an EL attribute, Vue will automatically mount the Vue instance for us after it is created.
  • In the second way, we manually mount the Vue instance by executing the $mount() method after the Vue instance is created. The method parameters also specify the actual DOM we want to mount.

The two creation methods are equivalent. Either way, mount() is called, so we know that the component is mounted on mount(), so we know that the component is mounted on mount(), so we know that the component is mounted on the mount() method, $mount() = $mount();

$mount() is the method defined on the Vue prototype
Vue.prototype.$mount = function (el, hydrating) {
    // find that we need to mount to the DOM element
    el = el && inBrowser ? query(el) : undefined;
    return mountComponent(this, el, hydrating)
  };
Copy the code

$mount() checks out the DOM element to which we want to mount it, and then calls mountComponent to actually mount it:

function mountComponent (
vm,
el,
hydrating
) {
    // The DOM element to be mounted is placed on the Vue instance first. This operation is meaningless if the EL attribute is already provided when we define the Vue
    vm.$el = el;
    
    // First check if there is a render function on the Vue instance, if not, use a default render function (createEmptyVNode) and throw a warning.
    if(! vm.$options.render) { vm.$options.render = createEmptyVNode; {/* istanbul ignore if */
            if ((vm.$options.template && vm.$options.template.charAt(0)! = =The '#') ||
                vm.$options.el || el) {
                warn(
                    'You are using the runtime-only build of Vue where the template ' +
                    'compiler is not available. Either pre-compile the templates into ' +
                    'render functions, or use the compiler-included build.',
                    vm
                );
            } else {
                warn(
                    'Failed to mount component: template or render function not defined.', vm ); }}}// Triggers the Vue instance's lifecycle hook beforeMount
    callHook(vm, 'beforeMount');

    var updateComponent;
    
    // If performance monitoring is configured, we will skip it because we will not use it in our normal development
    if (config.performance && mark) {
        updateComponent = function () {
            var name = vm._name;
            var id = vm._uid;
            var startTag = "vue-perf-start:" + id;
            var endTag = "vue-perf-end:" + id;

            mark(startTag);
            var vnode = vm._render();
            mark(endTag);
            measure(("vue " + name + " render"), startTag, endTag);

            mark(startTag);
            vm._update(vnode, hydrating);
            mark(endTag);
            measure(("vue " + name + " patch"), startTag, endTag);
        };
    } 
    
    // Call the update function where the mount is performed
    else {
        updateComponent = function () {
            vm._update(vm._render(), hydrating);
        };
    }

    // Create Watcher to listen for data changes and implement Vue responsiveness
    new Watcher(vm, updateComponent, noop, {
        before: function before () {
            if(vm._isMounted && ! vm._isDestroyed) { callHook(vm,'beforeUpdate'); }}},true /* isRenderWatcher */);
    hydrating = false;

    if (vm.$vnode == null) {
        vm._isMounted = true;
        
        // The Vue instance life cycle hook mounted
        callHook(vm, 'mounted');
    }
    return vm
}
Copy the code

As you can see from the above code, there are five stages of mount:

  • Check if there are render functions
  • Trigger lifecycle hooks beforeMount()
  • Mount the element onto the real DOM by executing the _update() function
  • Create Watcher, the implementation of Vue responsive principle, this part of the content can see my previous article: Vue source code analysis ① responsive principle
  • Hook mounted()

The third stage is what we really care about, so we examine the _update() function:

Vm._update () requires two parameters, vm._render() and a hydrating (Boolean).

Execute vm._render(), which is the render function of the Vue instance, and return a VNode (virtual DOM) after execution

// A Vnode is a Vnode generated by executing the render function
Vue.prototype._update = function (vnode, hydrating) {
    var vm = this;
    var prevEl = vm.$el;
    var prevVnode = vm._vnode;
    var restoreActiveInstance = setActiveInstance(vm);
    vm._vnode = vnode;
    
    // If there is a preVNode, the render function has not been executed for the first time, then the old and new vNodes need to be compared
    if(! prevVnode) {// initial render
        vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
    } else {
        // updates
        vm.$el = vm.__patch__(prevVnode, vnode);
    }
    
    restoreActiveInstance();
    
    // If the Vue instance has been previously mounted to other DOM elements, disconnect them
    if (prevEl) {
        prevEl.__vue__ = null; } / Set the Vue instance to the _Vue_ attribute of the DOM element to be mountedif (vm.$el) {
        vm.$el.__vue__ = vm;
    }
    
    // If the Vue instance (component) has a parent component, mount the parent component to the DOM element as well
    if(vm.$vnode && vm.$parent && vm.$vnode === vm.$parent._vnode) { vm.$parent.$el = vm.$el; }}Copy the code

As we can see from the above code, the actual mount operation is performed on the _patch_ function and the Vue instance is saved on the properties of the mounted DOM element.

conclusion