渲染器与响应系统的结合

function renderer(domString, container) {
  container.innerHTML = domString
}

const count = ref(1)

effect(() => {
  renderer(`<h1>${count.value}</h1>`,
    document.getElementById('app'))
})

count.value++

以上代码即为渲染器与响应系统的结合的大体原理,当然其中很多细节后面展现。

渲染器的基本概念

渲染器(renderer)的作用是把虚拟DOM渲染为特定平台上的真实元素

其他都是一些概念,不再赘述

自定义渲染器

const vnode = {
  type: 'h1',
  children: 'hello'
}
// 在创建 renderer 时传入配置项
const renderer = createRenderer({
  // 用于创建元素
  createElement(tag) {
    return document.createElement(tag)
  },
  // 用于设置元素的文本节点
  setElementText(el, text) {
    el.textContent = text
  },
  // 用于在给定的 parent 下添加指定元素
  insert(el, parent, anchor = null) {
    parent.insertBefore(el, anchor)
  }
})
// 调用 render 函数渲染该 vnode
renderer.render(vnode, document.querySelector('#app'))

function createRenderer() {// 通过 options 得到操作 DOM 的 API
  const {
    createElement,
    insert,
    setElementText
  } = options

  function patch(n1, n2, container) {
    // 如果 n1 不存在,意味着挂载,则调用 mountElement 函数完成挂载
    if (!n1) {
      mountElement(n2, container)
    } else {
      // n1 存在,意味着打补丁,暂时省略
    }
  }

  function mountElement(vnode, container) {
    // 调用 createElement 函数创建元素
    const el = createElement(vnode.type)
    if (typeof vnode.children === 'string') {
      // 调用 setElementText 设置元素的文本节点
      setElementText(el, vnode.children)
    }
    // 调用 insert 函数将元素插入到容器内
    insert(el, container)
  }

  function render(vnode, container) {
    if (vnode) {
      patch(container._vnode, vnode, container)
    } else {
      if (container._vnode) {
        container.innerHTML = ''
      }
    }
    container._vnode = vnode
  }

  return {
    render
  }
}

上述代码是本章自定义一个渲染器的基本实现。

  1. 为了兼容不同平台,对于DOM的增删改查等方法通过参数的方式传入渲染器,使其支持普通平台上对于vnode的渲染兼容
  2. patch函数内区分是初次挂载还是打补丁