《Vue.js设计与实现》 第七章 渲染器的设计
7.1 渲染器与响应系统的结合
最简单的渲染器及其使用
// 渲染器
function renderer(domString, container) {
container.innerHTML = domString
}
// 使用
let count = 1
renderer(`<h1>${count}</h1>`, document.getElementById('app'))
渲染器与响应式系统结合
const count = ref(1)
effect(() => {
renderer(`<h1>${count.value}</h1>`, document.getElementById('app'))
})
count.value++
7.2 渲染器的基本概念
renderer 来表达“渲染器”
render 来表达“渲染”
mount(挂载):渲染器把虚拟 DOM 节点渲染为真实 DOM 节点的过程。
patch:render() 函数里 执行patch,patch() 既可以用来打补丁,也可以用来执行挂载。
7.3 自定义渲染器
最简单的渲染器的使用
const vnode = {
type: 'h1',
children: 'hello'
}
// 创建一个渲染器
const renderer = createRenderer()
// 调用 render 函数渲染 vnode
renderer.render(vnode, document.querySelector('#app'))
渲染器的定义
function createRenderer() {
function patch(n1, n2, container) {
// to-do 渲染逻辑
}
function render(vnode, container) {
if (vnode) {
patch(container._vnode, vnode, container)
} else {
if (container._vnode) {
container.innerHTML = ''
}
}
container._vnode = vnode
}
return {
render
}
}
渲染器逻辑
function patch(n1, n2, container) {
// 挂载-n1不存在
if (!n1) {
mountElement(n2, container)
} else {
// 打补丁-n1存在
// to-do 打补丁逻辑
}
}
挂载节点
function mountElement(, container) {
// 创建 DOM 元素
const el = document.createElement(vnode.type)
// 处理子节点,如果子节点是字符串,代表元素具有文本节点
if (typeof vnode.children === 'string') {
// 因此只需要设置元素的 textContent 属性即可
el.textContent = vnode.children
}
// 将元素添加到容器中
container.appendChild(el)
}
如果要设计成不依赖于浏览器平台的通用渲染器,可以将document.createElement、el.textContent 以及 appendChild 等浏览器特有的API,抽离出来。使用时传入特定平台的方法即可。