Skip to main content

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#

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();}

渲染器 patch#

undingable...