Skip to content

第七章:渲染器的设计

渲染器的基本概念

  • renderer:渲染器,其作用是把 虚拟 DOM 渲染成特定平台上的真实元素。
  • render:动词,表示渲染。
  • virtual DOM:虚拟 DOM,通常简写成 vdom
  • virtual Node:虚拟节点,简写成 vnode,是 vdom 上的任何一个子树,因此 vdom 和 vnode 可以替换使用。
  • mount:渲染器把 vdom 渲染成真实元素的过程称为 挂载
javascript
function createRenderer() {
  function mountElement(vnode, container) {
    const el = document.createElement(vnode.type);
    if (typeof vnode.children === 'string') {
      el.textContent = vnode.children;
    }
    container.appendChild(el);
  }

  /**
   *
   * @param n1 旧的 vnode
   * @param n2 新的 vnode
   * @param container 挂载的节点
   */
  function patch(n1, n2, container) {
    // 没有 n1 证明是第一次挂载
    if (!n1) {
      mountElement(n2, container);
    } else {
      // TODO:打补丁
    }
  }

  function render(vnode, container) {
    if (vnode) {
      // 新 vnode 存在,将其与旧 vnode 一起传递给 patch 函数,进行打补丁
      patch(container._vnode, vnode, container);
    } else {
      if (container._vnode) {
        // 旧 vnode 存在,新的不存在,说明是卸载操作 - unmount
        container.innerHTML = '';
      }
    }
    container._vnode = vnode;
  }
  return {
    render
  };
}

const rendered = createRenderer();
rendered.render(vnode, document.querySelector('#renderId'));

自定义渲染器

可以在创建渲染器时将一些基础操作传入

javascript
function createRenderer(options) {
  const { createElement, setElementText, insert } = options;

  function mountElement(vnode, container) {
    const el = createElement(vnode.type);
    if (typeof vnode.children === 'string') {
      setElementText(el, vnode.children);
    }
    insert(el, container);
  }

  function patch(n1, n2, container) {
    /** */
  }

  function render(vnode, container) {
    /** */
  }
  return {
    render
  };
}

const rendered = createRenderer({
  createElement(tag) {
    return document.createElement(tag);
  },
  setElementText(el, text) {
    el.textContent = text;
  },
  insert(el, parent, anchor = null) {
    parent.insertBefore(el, anchor);
  }
});