vue-design
#
组件的产出是什么有個疑問:
import { h, init } from "snabbdom";// init 方法用来创建 patch 函数const patch = init([]);
const MyComponent = (props) => { return h("h1", props.title);};
// 组件的产出是 VNodeconst prevVnode = MyComponent({ title: "prev" });// 将 VNode 渲染成真实 DOMpatch(document.getElementById("app"), prevVnode);
snabbdom
API 里 function patch 返回 VNode 。所以是渲染成真实 DOM 吗?
snabbdom源碼
return function patch(oldVnode: VNode | Element, vnode: VNode): VNode { // ... some codes return vnode;};
为何组件要从直接产出 html
变成产出 Virtual DOM
呢?其原因是 Virtual DOM
带来了 分层设计,它对渲染过程的抽象,使得框架可以渲染到 web
(浏览器) 以外的平台,以及能够实现 SSR
等。
至于 Virtual DOM
相比原生 DOM 操作的性能,这并非 Virtual DOM
的目标,确切地说,如果要比较二者的性能是要“控制变量”的,例如:页面的大小、数据变化量等。
至此我们要达成的共识:相比早先“模板引擎”返回 HTML 字符串,组件的产出就是 Virtual DOM。
以上。
#
设计 VNode目标:使用 flags
属性来存储 VNode 的类型,类似的,使用 childFlags
来存储子节点的类型。熟悉 <<
、&
、|
运算的使用。
简化的VNode对象
export interface VNode { _isVNode: true; el: Element | null; flags: VNodeFlags; tag: string | FunctionalComponent | ComponentClass | null; data: VNodeData | null; children: VNodeChildren; childFlags: ChildrenFlags;}
至此,h
函数已经可以创建任何类型的 VNode
对象了,有了 VNode
对象,下一步要做的就是将 VNode
对象渲染成真实 DOM。
以上。
#
渲染器挂载#
挂载普通标签元素#
class 的处理<template> <div class="cls-a" :class="dynamicClass"></div></template>
在编译器对模板进行编译时,我们把非绑定和绑定的 class
属性值合并,最终得到类名列表字符串。
序列化函数
function normalizeClass(classValue: any): string { let res: string = ""; if (typeof classValue === "string") { res = classValue; } else if (Array.isArray(classValue)) { for (let i = 0; i < classValue.length; i++) { res += normalizeClass(classValue[i]) + " "; } } else if (typeof classValue === "object") { for (const name in classValue) { if (classValue[name]) { res += name + " "; } } }
return res.trim();}
#
渲染器 patchundingable...