An overview of the

To achieve the responsive mode, Vue uses the render function to generate vNodes, uses the diff algorithm to compare the old and new vNodes, and finally updates to the real DOM.

Since it is compiled rather than listening, vNode has no object to compare to and generates the real DOM directly from vNode.

A Vnode is a node on the Vdom, which is an abstraction of the real DOM. In a Vue, we can compare the old and new VNodes with the Vdom to get the operations that need to update the real DOM, and perform these operations through the Vue framework. So we can focus more on business logic.

Compilation phase

This phase parses the template and converts the template to the render function through three processes:

  1. Parse: Parses strings from the Template template to obtain data such as instructions, class, and style to form the AST
  2. Optimize, the phase used to optimize the patch phase to mark the static property of the node as static
  3. Generate, convert AST into Render funtion string, and finally get render string and staticRenderFns string

With vue-CLI tools, you can use Webpack to convert the template to the Render function and staticRenderFns function during the packaging process

The relationship between the render string and the render function

The render function contains the render string inside:

function render(vm) {
  with(vm) {
    eval(render_string)
  }
}
Copy the code

Mount the node

The final step in Vue instantiation is to mount the node. This stage will be divided into two steps:

  1. Get vNodes using the render function
  2. Pass vNode to the patch function to generate the real DOM and mount it to the page

When the render function is executed

When will the render function be executed again?

The getters for Render-Watcher instances execute the Render function:

updateComponent = (a)= > {
  vm._update(vm._render(), hydrating)
}

new Watcher(vm, updateComponent, noop, {
  before () {
    if (vm._isMounted) {
      callHook(vm, 'beforeUpdate')}}},true /* isRenderWatcher */)
Copy the code

So, the render function will be executed when:

  1. When the Vue is initialized, it is executed once
  2. The render function is also triggered when the template data object to observe is updated

The key to the render function is _createElement, which returns a VNode. It returns either a normal VNode or a component VNode, depending on whether the tag name exists in a registered component:

export function _createElement (context: Component, tag? : string | Class
       
         | Function | Object, data? : VNodeData, children? : any, normalizationType? : number
       ) :VNode | Array<VNode> {
    / /...
  let vnode, ns
  if (typeof tag === 'string') {
    let Ctor
    ns = (context.$vnode && context.$vnode.ns) || config.getTagNamespace(tag)
    if (config.isReservedTag(tag)) {
      // platform built-in elements
      vnode = new VNode(
        config.parsePlatformTagName(tag), data, children,
        undefined.undefined, context
      )
    } else if (isDef(Ctor = resolveAsset(context.$options, 'components', tag))) {
      // component
      vnode = createComponent(Ctor, data, context, children, tag)
    } else {
      // unknown or unlisted namespaced elements
      // check at runtime because it may get assigned a namespace when its
      // parent normalizes children
      vnode = new VNode(
        tag, data, children,
        undefined.undefined, context
      )
    }
  } else {
    // direct component options / constructor
    vnode = createComponent(tag, data, context, children)
  }
  if (Array.isArray(vnode)) {
    return vnode
  } else if (isDef(vnode)) {
    if (isDef(ns)) applyNS(vnode, ns)
    if (isDef(data)) registerDeepBindings(data)
    return vnode
  } else {
    return createEmptyVNode()
  }
}
Copy the code

Timing of patch function execution

Render (vm._update(vm._render(), hydrating));

  1. When the Vue is initialized, the real DOM is generated and mounted to the Document
  2. When the observed data object in the Template is updated, the old and new vNodes are compared and the real DOM corresponding to the new vNode is returned
Vue.prototype._update = function (vnode: VNode, hydrating? : boolean) {
  const vm: Component = this
  const prevEl = vm.$el
  const prevVnode = vm._vnode
  const prevActiveInstance = activeInstance
  activeInstance = vm
  vm._vnode = vnode
  // Vue.prototype.__patch__ is injected in entry points
  // based on the rendering backend used.
  if(! prevVnode) {// Initialize render
    vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */)}else {
    // Update render
    vm.$el = vm.__patch__(prevVnode, vnode)
  }
  activeInstance = prevActiveInstance
  // 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.
}
Copy the code

The core of the updated patch function is the DIff algorithm, which is similar to git’s DIff instruction. The general logic is as follows:

By comparing old and new VNodes, you can find all the operations needed to update the real DOM, such as adding, deleting, and replacing nodes. These DOM updates are then performed through the Vue framework and the updated DOM is returned.

reference

How does the template template Compile with vue.js technology reveal