FlexUI Core 详细设计方案

1. 概述

@flexui/core 是 FlexUI 跨端组件框架的核心模块,提供一套声明式、组件化的 UI 开发基础设施。它不依赖特定运行环境,可在 Web、HarmonyOS、Android、iOS 等多个后端运行。

1.1 核心特性

  • 多后端支持:通过 Backend 抽象层适配 DOM、Native、自定义渲染环境
  • 组件系统:完整的自定义组件定义、生命周期、属性/数据/方法管理
  • 模板引擎:编译时生成高效的增量更新代码,运行时仅执行数据→DOM 的同步更新
  • Shadow Tree:每组件独立的 Shadow Root,支持 slot 分发和样式隔离
  • 数据绑定:基于 setData 的同步数据驱动更新,支持深层路径观测
  • 事件系统:自定义事件、冒泡/捕获、外部事件触发
  • TypeScript 优先:链式 API 提供完整类型推断

1.2 包信息

字段
包名 @flexui/core
版本 0.1.0
语言 TypeScript
构建 Rollup
测试 Jest
入口 dist/flexui.all.js (CJS) / dist/flexui.all.es.js (ESM)

2. 架构设计

2.1 整体架构

┌──────────────────────────────────────────────────────────┐
│                      应用层 (App)                          │
├──────────────────────────────────────────────────────────┤
│  ComponentSpace    │  Component  │  Behavior  │  Event   │
├──────────────────────────────────────────────────────────┤
│  Template Engine   │  ShadowRoot │  Element   │  Node    │
├──────────────────────────────────────────────────────────┤
│  DataProxy         │  DataPath   │  DataUtils │          │
├──────────────────────────────────────────────────────────┤
│  Backend (抽象层)  │  DOM Backend│  Native B. │ Empty B. │
└──────────────────────────────────────────────────────────┘

2.2 模块依赖关系

index.ts (入口 + registerBehavior/registerElement/createElement)
  ├── component.ts        — 组件实例、组件定义
  ├── component_space.ts  — 组件空间、中间件钩子
  ├── behavior.ts         — 行为定义 (Builder 模式)
  ├── element.ts          — 元素基类 (DOM 节点抽象)
  ├── shadow_root.ts      — Shadow Root 实现
  ├── node.ts             — 节点工具函数
  ├── text_node.ts        — 文本节点
  ├── virtual_node.ts     — 虚拟节点
  ├── native_node.ts      — 原生节点
  ├── template_engine.ts  — 模板接口定义
  ├── tmpl/               — 模板实现
  │   ├── index.ts        — FlexUITemplate / FlexUITemplateEngine
  │   ├── native_rendering.ts — 原生渲染模板
  │   └── proc_gen_wrapper.ts — 过程生成包装器
  ├── data_proxy.ts       — 数据代理与观测
  ├── data_path.ts        — 数据路径解析
  ├── data_utils.ts       — 数据工具函数
  ├── event.ts            — 事件类
  ├── backend/            — 后端抽象
  ├── class_list.ts       — 样式类列表与作用域
  ├── relation.ts         — 组件关系
  ├── selector.ts         — 选择器解析
  ├── mutation_observer.ts— MutationObserver 实现
  ├── external_shadow_tree.ts — 外部 Shadow Tree
  ├── global_options.ts   — 全局配置
  ├── dev_tools.ts        — 开发者工具接口
  └── warning.ts          — 警告与错误

3. 核心模块设计

3.1 ComponentSpace(组件空间)

组件空间是全局组件注册中心,管理所有组件定义和行为定义。

ComponentSpace
  ├── defineComponent()    → 定义组件 (返回 ComponentDefinition)
  ├── defineBehavior()     → 定义行为 (返回 Behavior)
  ├── 全局单例: getDefaultComponentSpace()
  └── MiddlewareHook        → 中间件钩子

设计要点

  • 每个应用通常使用一个默认 ComponentSpace
  • 支持链式 API (space.define().template(...).data(...))
  • MiddlewareHook 允许拦截组件的创建、更新等生命周期

3.2 Component(组件实例)

组件是框架的核心运行单元。每个组件拥有独立的 Shadow Tree。

GeneralComponent (抽象接口)
  ├── Component (核心实现, ~55KB)
  │   ├── 数据管理: setData / applyDataUpdates
  │   ├── 生命周期: created / attached / ready / detached / moved
  │   ├── 属性系统: property definitions / property values
  │   ├── 方法调用: callMethod
  │   ├── 事件触发: triggerEvent
  │   ├── 节点树操作: appendChild / insertBefore / removeChild
  │   ├── Shadow Root: createShadowRoot / getShadowRoot
  │   ├── 关系系统: RelationType
  │   └── 模板实例: templateInstance / applyTemplateUpdate
  ├── ComponentDefinition<TData, TProperty, TMethod>
  └── ComponentInstance = Component + 类型化的数据/属性/方法

关键设计决策

  • setData 是同步的:调用 setData 后,数据和界面在同一调用栈内更新,不存在异步批量更新
  • 每组件独立 Shadow Tree:组件间通过属性 (properties) 和事件 (events) 通信
  • 生命周期完整:created → attached → ready → detached 覆盖组件全生命周期

3.3 Backend(后端抽象)

Backend 是框架与环境之间的抽象层,使得同一份组件代码可以运行在不同环境。

// 后端模式
enum BackendMode {
  Domlike,    // 类 DOM 环境 (浏览器)
  Composed,   // 组合后端
  Native,     // 原生渲染
}

// 后端接口
interface backend {
  createElement(context, name, stylingName, ownerShadowRoot): Element
  createTextNode(context, content, ownerShadowRoot): TextNode
  createFragment(context, ownerShadowRoot): Fragment
  // ...
}

// 组合后端 = DOM + Shadow Backend
interface composedBackend {
  domBackend: backend
  shadowBackend: backend
}

后端类型

Backend 用途
CurrentWindowBackendContext 浏览器 DOM 环境
EmptyBackendContext 无渲染输出 (测试/SSR)
EmptyComposedBackendContext 无渲染的组合后端
自定义 Backend Native、Shadow Sync 等

3.4 Template Engine(模板引擎)

模板引擎将 HXML 模板编译为高效的 JavaScript 过程生成代码 (ProcGen)。

TemplateEngine
  └── createInstance(elem, createShadowRoot) → TemplateInstance

Template (接口)
  ├── createInstance()    → 创建模板实例
  └── updateTemplate()    → 更新模板内容 (开发时热重载)

FlexUITemplateEngine      → 入口,根据 externalComponent 选择模板类型
  ├── FlexUITemplate      → 标准组件模板
  └── FlexUITemplateDOM   → 原生渲染模板 (external component)

ProcGen 过程生成

  • 模板编译为 ProcGen 函数组,每个函数生成特定类型的节点操作
  • C (Creation): 创建 DOM 节点、文本节点、条件组、循环、slot
  • B (Binding): 数据绑定映射,指定哪些数据路径触发哪些更新
  • 支持条件渲染 (has:if)、列表渲染 (has:for)、插槽 (slot)

3.5 DataProxy(数据代理)

数据代理系统负责监听数据变化并触发界面更新。

DataGroup              → 数据组,包含多个数据路径
DataObserver           → 数据观测器,监听特定路径
DataChange             → 数据变更事件
DataUpdateCallback     → 数据更新回调
PropertyChange         → 属性变更事件

DeepCopyStrategy       → 深拷贝策略
  ├── DEFAULT          → 默认深拷贝
  ├── NO_DEEP_COPY      → 不深拷贝
  └── 自定义策略

数据路径:支持点分隔路径 (a.b.c) 和数组索引路径 (a[0].b)

3.6 Event System(事件系统)

Event<TDetail>
  ├── type: string         → 事件类型
  ├── detail: TDetail      → 事件数据
  ├── bubbles: boolean     → 是否冒泡
  ├── composed: boolean    → 是否穿透 Shadow Root
  ├── capturePhase: boolean→ 是否捕获阶段
  └── eventPhase: EventPhase → 当前阶段 (None/Capturing/AtTarget/Bubbling)

EventBubbleStatus
  ├── stopped: boolean     → 是否已停止冒泡
  ├── mutated: boolean     → 是否已修改事件数据
  └── noDefault: boolean   → 是否已阻止默认行为

事件触发方式

  • triggerEvent(name, detail, options) — 组件内部触发
  • triggerExternalEvent(name, detail, options) — 外部触发

3.7 ShadowRoot(Shadow Root)

ShadowRoot
  ├── SlotMode              → slot 分发模式
  │   ├── SingleSlot        → 单 slot
  │   └── MultiSlot         → 多 slot (命名 slot)
  ├── owner: GeneralComponent
  ├── host: Element
  └── children: Element[]

样式隔离

  • ClassList — 样式类按键管理
  • StyleScopeId — 样式作用域 ID
  • StyleScopeManager — 样式作用域管理器
  • 每个组件有独立的样式作用域,避免样式冲突

3.8 Relation(组件关系)

RelationType              → 关系类型定义
RelationListener          → 关系监听器
RelationFailedListener    → 关系失败监听器

支持组件间的父子/兄弟关系绑定,用于表单关联、组件联动等场景。

3.9 MutationObserver

提供与 Web API 兼容的 MutationObserver 实现,监听 Shadow Tree 变更:

MutationObserver
  ├── observe(target, options)
  ├── disconnect()
  └── takeRecords() → MutationRecord[]

3.10 DevTools

DevTools
  ├── InspectorDevTools     → 组件树检查
  └── PerformanceDevTools   → 性能测量

MountPointEnv               → 挂载点环境

4. 数据流

用户调用 setData(path, value)
  │
  ├── DataProxy 记录变更 → DataChange 事件
  │
  ├── DataObserver 通知所有监听该路径的观察者
  │
  ├── TemplateInstance 收到更新通知
  │   └── 执行 ProcGen Binding 函数 → 增量更新 DOM/Shadow Tree
  │
  └── Backend 将变更应用到实际渲染环境

关键特性

  • 同步更新:setData → DOM 更新在同一执行栈内完成
  • 路径级精确更新:仅更新受影响的节点,非全量刷新
  • 批量更新支持:多次 setData 合并为一次 DOM 更新

5. 公开 API

5.1 入口函数

// 注册 Behavior (无模板的组件逻辑)
registerBehavior(def) → Behavior

// 注册组件 (含模板的完整组件)
registerElement(def) → ComponentDefinition

// 创建组件实例
createElement(tagName, compDef?) → GeneralComponent

// 触发事件
triggerEvent(name, detail, options)
triggerExternalEvent(name, detail, options)

5.2 核心类型导出

类别 导出类型
Backend BackendMode, GeneralBackendContext, GeneralBackendElement, backend, composedBackend, domlikeBackend
组件 Component, ComponentDefinition, GeneralComponent, GeneralComponentDefinition
数据 DataGroup, DataObserver, DataChange, DataValue, PropertyChange
事件 Event, EventBubbleStatus, EventListener, ShadowedEvent, EventPhase
节点 Element, Node, TextNode, VirtualNode, NativeNode, ShadowRoot
其他 ComponentSpace, templateEngine, ClassList, MutationObserver, DevTools

6. 构建与测试

6.1 构建

# 标准构建 (CJS + ESM + 类型声明)
cd packages/flexui && pnpm run build

# 开发构建 (含调试信息)
cd packages/flexui && FLEXUI_ARGS=--dev pnpm run build

# 仅生成类型声明
FLEXUI_ARGS=dts rollup --config rollup.config.ts

构建工具链:Rollup + TypeScript + @flexui/template-compiler (devDependency)

6.2 测试

cd packages/flexui && pnpm run test           # 运行测试
cd packages/flexui && pnpm run coverage       # 覆盖率报告

7. 设计决策

7.1 为什么 setData 是同步的?

与 React 的异步批量更新 (fiber) 不同,FlexUI 选择同步更新策略:

  • 简单直观:数据变更后立即可见,无需理解调度机制
  • 小程序兼容:与微信小程序 setData 语义一致
  • 性能均衡:路径级精确更新策略避免了全量 diff

7.2 为什么使用 ProcGen 过程生成?

  • 编译时优化:模板在构建时编译为最优的 JavaScript 更新函数
  • 运行时轻量:运行时无需解析模板、无需 diff 算法,仅执行预生成的函数
  • 增量更新:每个数据路径绑定到特定的 DOM 操作,更新粒度精确

7.3 为什么有 Behavior 和 Component 两个概念?

  • Behavior:可复用的组件逻辑单元 (data + properties + methods + lifetimes)
  • Component:包含模板的完整组件
  • Behavior 可以组合 (类似 mixin/trait),Component 继承 Behavior 并附加模板

分离后的好处:

  • Behavior 可在多个组件间共享逻辑
  • 支持 relation 等高级组件间交互模式

7.4 后端抽象设计

通过 Backend 接口抽象,FlexUI 可以运行在任何环境:

  • Web:直接操作 DOM
  • HarmonyOS:通过 flexui-engine 操作原生渲染节点
  • Native:通过 Shadow Sync 跨越 JS Bridge 同步节点树
  • 测试:EmptyBackend 提供无副作用的测试环境