This is the 23rd day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

The core process of Vue initial rendering is roughly as follows: parsing the template to generate the render function, calling the render function to generate the virtual DOM, and creating real DOM rendering through the virtual DOM to display in the browser

The core processes

Now that the render function is generated, the mount process starts with the $mount function, adding the mountComponent function as the mount entry point

/** * render process */
Vue.prototype.$mount = function (_el) {
  const vm = this;
  const ops = this.$options;
  const el = document.querySelector(_el);

  if(! ops.render) {// There is no render function, need to compile it
    let template = ops.template;

    if(! template && el) {// No template is passed and el is passed
      template = el.outerHTML; // use the content of el as a template
    }

    // Convert template to render
    const { render } = compileToFunction(template);
    // 
    ops.render = render;
  }
  
  // Mount the component
  mountComponent(vm, el);
};
Copy the code

The initial rendering flow is something that needs to be done within the Vue lifecycle, the mountComponent function is extracted into lifecycle

export function mountComponent(vm, el) {
  const options = vm.$options;
  vm.$el = el; // Real DOM elements
  // todo ...
}
Copy the code

There are two main things you do in this function

  1. callrenderThe function generates the virtual DOM
  2. Create a real DOM rendering from the virtual DOM

_render

Note that _render internally calls the render function above

Vue.prototype._render = function () {
  const vm = this;
  const { render } = vm.$options;
  
  // render retrievals the value on the instance and returns vnode
  return render.call(vm);
};
Copy the code

_update

The virtual DOM is returned by calling _render, the real DOM is created and rendered, and important operations are extracted into the Patch function

Vue.prototype._update = function (vnode) {
  const vm = this;

  // We need to create real nodes with virtual nodes instead of real $el
  vm.$el = patch(vm.$el, vnode);
};
Copy the code

Here you get the mountComponent core work

vm._update(vm._render());
Copy the code

render

The data structure returned when Render is called

function render() {
  with(this) {
    return _c('div', {
      attrs: {
        "id": "app"
      }
    }, [_c('p', [_v("hi " + _s(msg))]), _v(" hello")]}}Copy the code

These _c, _v and other functions return the virtual DOM. Let’s see how these functions are implemented

Encapsulate the implementation of _c, _v, _s and other functions in SRC /render.js and execute them by referencing them in SRC /index.js

Add two lines of code to index.js

+++ import { renderMixin } from "./render"; / / reference
+++ renderMixin(Vue); / / execution
Copy the code

Render. Js general structure

export function renderMixin(Vue) {
  /** * _c creates the element's virtual node * _v creates the text's virtual node * _s json.stringify */

  Vue.prototype._c = function () {};

  Vue.prototype._v = function (text) {};

  Vue.prototype._s = function (val) {};
}
Copy the code

Creating a virtual DOM

_c and _v are used to create what are often called virtual nodes. Let’s start with vnode, which creates the virtual DOM

const vnode = (tag, data, key, children, text) = > {
  return {
    tag,
    data,
    key,
    children,
    text,
  };
};
Copy the code

_c: the virtual node used to create the element, internally based on createElement

/** * Creates a virtual node for the element */
const createElement = (tag, data, ... children) = > {
  let key = data && data.key;

  if (key) {
    delete data.key;
  }

  return vnode(tag, data, key, children, undefined);
}

const _c = function () {
  returncreateElement(... arguments); };Copy the code

_v: the virtual node used to create text, internally created from createTextNode

/** * Create a virtual node for text */
const createTextNode = (text) = > {
  return vnode(undefined.undefined.undefined.undefined, text);
}

const _v = function (text) {
  return createTextNode(text);
};
Copy the code

_s: it does something relatively simple, serializing strings

const _s =  (val) = > {
  return val === null ? "" : typeof val === "object" ? JSON.stringify(val): val;
};
Copy the code

SRC /core/instance/render-helpers/index.js SRC /core/instance/render-helpers/ index.php

export function installRenderHelpers (target) { target._o = markOnce target._n = toNumber target._s = toString target._l = renderList target._t = renderSlot target._q  = looseEqual target._i = looseIndexOf target._m = renderStatic target._f = resolveFilter target._k = checkKeyCodes target._b = bindObjectProps target._v = createTextVNode target._e = createEmptyVNode target._u = resolveScopedSlots target._g = bindObjectListeners target._d = bindDynamicKeys target._p = prependModifier }Copy the code

Now that the initial rendering of the Vue is complete and several common functions for creating the virtual DOM have been introduced, we need to look at how to create the real DOM from the virtual DOM and render it to the browser