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 节点、文本节点、条件组、循环、slotB(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— 样式作用域 IDStyleScopeManager— 样式作用域管理器- 每个组件有独立的样式作用域,避免样式冲突
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 提供无副作用的测试环境