Rendering functions in the MVVM framework are created by compiling view templates, which are simply parsed to generate rendering functions.

directory

  1. What is the virtual Dom
  2. What is a render function
  3. DomDiff updates views efficiently
  4. 【 Render function 】The render module uses render functions to generate the virtual Dom from initialization data -> Create view page Html using the virtual Dom -> Once the data model changes, the rendering function is called again to generate a new virtual Dom and then do Dom Diff to update the view Html
  5. 【 Render function 】Initialize data -> Render (initialize data) -> Initialize the virtual DOM -> Initial view HTML -> Data changes -> Render (change data) -> New virtual DOM -> DOM Diff -> Update view HTML
  6. Template -> compiles to render function -> converts to virtual Dom
    1. Template -> render -> virtual Dom

What is the virtual Dom

1) dom

Dom has a large number of nodes, so the performance of directly querying and updating Dom is poor

2) virtual Dom

A way of representing the actual DOM with JavaScript Objects. Rerepresent the actual Dom with a JS object

What is a render function

In Vue we compile a view template into a render function and then convert it into a virtual Dom

Update views efficiently with DomDiff

Four, achieve the rendering function [key]

In Vue we compile a view template into a render function and then convert it into a virtual Dom

4.1) The rendering process is usually divided into three parts:

  • RenderPhase: The render module uses render functions to generate the virtual Dom from initialization data
  • MountPhase: Create view page Html using the virtual Dom
  • PatchPhase: Once the data model changes, the rendering function will be called again to generate a new virtual Dom and then do Dom Diff to update the view Html
mount: function (container) {
    const dom = document.querySelector(container);
    const setupResult = config.setup();
    const render = config.render(setupResult);

    let isMounted = false;
    let prevSubTree;
    watchEffect(() = > {
      if(! isMounted) { dom.innerHTML ="";
        // mount
        isMounted = true;
        const subTree = config.render(setupResult);
        prevSubTree = subTree;
        mountElement(subTree, dom);
      } else {
        // update
        constsubTree = config.render(setupResult); diff(prevSubTree, subTree); prevSubTree = subTree; }}); }Copy the code
4.1.1) 1 Render Phase

The render module uses render functions to generate the virtual Dom from initialization data

render(content) {
  return h("div".null, [
    h("div".null.String(content.state.message)),
    h(
      "button",
      {
        onClick: content.click,
      },
      "click"),]); },Copy the code
4.1.2) 2 Mount Phase

Create view page Html using the virtual Dom

function mountElement(vnode, container) {
  // Render to a real DOM node
  const el = (vnode.el = createElement(vnode.type));

  / / processing props
  if (vnode.props) {
    for (const key in vnode.props) {
      const val = vnode.props[key];
      patchProp(vnode.el, key, null, val); }}// Handle children
  if (Array.isArray(vnode.children)) {
    vnode.children.forEach((v) = > {
      mountElement(v, el);
    });
  } else {
    insert(createText(vnode.children), el);
  }

  // Insert into the view
  insert(el, container);
}
Copy the code
4.1.3) 3 Patch Phase(Dom diff)

Once the data model changes, the rendering function is called again to generate a new virtual Dom and then do Dom Diff to update the view Html

function patchProp(el, key, prevValue, nextValue) {
  // onClick
  // 1. If the first two values are on
  // 2. Consider it an event
  // 3. On is the corresponding event name
  if (key.startsWith("on")) {
    const eventName = key.slice(2).toLocaleLowerCase();
    el.addEventListener(eventName, nextValue);
  } else {
    if (nextValue === null) {
      el.removeAttribute(key, nextValue);
    } else{ el.setAttribute(key, nextValue); }}}Copy the code

Update views with DomDiff – Efficiently

function diff(v1, v2) {
  // 1. If the tag is different, just replace it
  // 2. If tag is the same
  // 1. Check whether the props are changed
  // 2. To detect children -
  const { props: oldProps, children: oldChildren = [] } = v1;
  const { props: newProps, children: newChildren = [] } = v2;
  if(v1.tag ! == v2.tag) { v1.replaceWith(createElement(v2.tag)); }else {
    const el = (v2.el = v1.el);
    / / contrast props
    // 1. The new node is not equal to the value of the old node -> direct assignment
    // 2. Delete all keys that do not exist in the new node
    if (newProps) {
      Object.keys(newProps).forEach((key) = > {
        if (newProps[key] !== oldProps[key]) {
          patchProp(el, key, oldProps[key], newProps[key]);
        }
      });

      // Go through the old node - "new node does not have, then delete all
      Object.keys(oldProps).forEach((key) = > {
        if(! newProps[key]) { patchProp(el, key, oldProps[key],null); }}); }/ / the children

    // newChildren -> string
    // oldChildren -> string oldChildren -> array

    // newChildren -> array
    // oldChildren -> string oldChildren -> array
    if (typeof newChildren === "string") {
      if (typeof oldChildren === "string") {
        if (newChildren !== oldChildren) {
          setText(el, newChildren);
        }
      } else if (Array.isArray(oldChildren)) {
        // Replace all the previous elementsv1.el.textContent = newChildren; }}else if (Array.isArray(newChildren)) {
      if (typeof oldChildren === "string") {
        // Clear the previous data
        n1.el.innerHTML = "";
        // Mount all the children out
        newChildren.forEach((vnode) = > {
          mountElement(vnode, el);
        });
      } else if (Array.isArray(oldChildren)) {
        // a, b, c, d, e -> new
        // a1,b1,c1,d1 -> old
        // If there are too many new, create a new one

        // a, b, c -> new
        // a1,b1,c1,d1 -> old
        // If there are many old ones, delete all the old ones
        const length = Math.min(newChildren.length, oldChildren.length);
        for (let i = 0; i < length; i++) {
          const oldVnode = oldChildren[i];
          const newVnode = newChildren[i];
          // Can be very complex
          diff(oldVnode, newVnode);
        }

        if (oldChildren.length > length) {
          // Indicates that there are many old nodes
          // Delete all of them
          for (leti = length; i < oldChildren.length; i++) { remove(oldChildren[i], el); }}else if (newChildren.length > length) {
          // Indicates that new has many nodes
          // Then you need to create the corresponding node
          for (let i = length; i < newChildren.length; i++) {
            mountElement(newChildren[i], el);
          }
        }
      }
    }
  }
}
Copy the code

reference

  • Vue source

conclusion

  • Virtual Dom – Rerepresents the actual Dom with JS objects
  • [Rendering function process]

Once the data model changes, the rendering function will be called again to generate a new virtual Dom, and then do Dom Diff to update the view Html

  • [Rendering function process]

Initialize data -> render -> initialize virtual DOM -> initial view HTML -> data changes -> render -> new virtual DOM -> DOM Diff -> update view HTML

  • Template -> compiles to render function -> converts to virtual Dom
  • Template -> render -> virtual Dom
  • Rendering functions in the MVVM framework are created by compiling view templates, which are simply parsed to generate rendering functions.