FlexUI ASCF 详细设计方案

1. 概述

@flexui/ascf 是 FlexUI 的 ASCF (Atomic Service Cross Framework) 接口适配器,为 @flexui/core 提供与小程序 HXML/CSS/JS 组件开发方式兼容的接口层。

1.1 设计目标

  • 接口兼容:提供与 MiniProgram 自定义组件接口一致的 API 风格
  • HXML/CSS 支持:结合 webpack 插件,支持 .hxml 模板和 .css 样式文件
  • ASCF 组件库:内置 ASCF 生态的预定义组件 (button, view, text, scroll-view 等)
  • 渐进迁移:允许开发者从 MiniProgram 生态平滑迁移到 FlexUI

1.2 包信息

字段 值
包名 @flexui/ascf
版本 0.1.0
语言 TypeScript
构建 Rollup
入口 dist/flexui_ascf.js / dist/flexui_ascf.es.js
组件入口 dist/flexui_ascf_components.js

2. 架构设计

┌──────────────────────────────────────────────────────┐
│                    应用代码 (HXML/CSS/JS)              │
├──────────────────────────────────────────────────────┤
│  @flexui/ascf (接口适配层)                             │
│  ├── Component()       → 组件定义 (类 MiniProgram API) │
│  ├── Behavior()        → 行为复用                      │
│  ├── Backend           → ASCF 运行时后端                │
│  ├── Space             → 组件空间管理                   │
│  ├── Builder           → 构建器链式 API                 │
│  └── components/       → 内置 ASCF 组件                │
├──────────────────────────────────────────────────────┤
│  @flexui/core (核心引擎)                               │
└──────────────────────────────────────────────────────┘

3. 核心模块

3.1 Component API

提供与 MiniProgram Component() 构造函数兼容的接口:

// ASCF 风格的组件定义
Component({
  data: { count: 0 },
  properties: { title: String },
  methods: {
    increment() { this.setData({ count: this.data.count + 1 }) }
  },
  lifetimes: {
    attached() { /* ... */ },
    detached() { /* ... */ },
  },
})

与 @flexui/core 的映射关系:

  • Component(options) → ComponentSpace.defineComponent(params)
  • Behavior(options) → ComponentSpace.defineBehavior(params)
  • this.setData() → GeneralComponent.setData()
  • this.triggerEvent() → GeneralComponent.triggerEvent()

3.2 Backend(ASCF 运行时后端)

backend.ts 提供 ASCF 运行环境的 Backend 实现:

ASCF Backend
  ├── 元素创建与销毁
  ├── 属性设置与样式应用
  ├── 事件绑定与分发
  └── 与 ASCF 原生层的通信

3.3 ComponentSpace(组件空间)

space.ts 封装了 ASCF 的组件注册和全局配置:

ASCF ComponentSpace
  ├── 全局组件注册: usingComponents
  ├── 全局样式: app.css
  ├── 环境变量: env.ts (设备信息、系统信息)
  └── 组件隔离策略: styleIsolation

3.4 Builder(构建器)

builder/ 目录提供与核心框架行为定义相关的构建器辅助功能。

3.5 内置组件

components/ 目录包含 ASCF 生态的预定义组件:

组件 说明
view 基础容器,对应 <div>
text 文本节点,支持 selectable
image 图片显示
button 按钮,支持多种样式
scroll-view 可滚动容器
input 输入框
textarea 多行输入
swiper 轮播组件
icon 图标组件

3.6 选择器查询 (SelectorQuery)

selector_query.ts 提供类 MiniProgram 的节点查询 API:

const query = this.createSelectorQuery()
query.select('.my-class').boundingClientRect()
query.selectAll('.item').fields({ rect: true, size: true })
query.exec((results) => { /* ... */ })

3.7 IntersectionObserver

intersection.ts 提供节点相交状态观测:

const observer = this.createIntersectionObserver()
observer.relativeTo('.container').observe('.target', (res) => {
  console.log(res.intersectionRatio)
})

3.8 MediaQuery

media_query.ts 提供媒体查询观测:

const observer = this.createMediaQueryObserver()
observer.observe({ minWidth: 375 }, (matches) => { /* ... */ })

3.9 ResizeObserver

resize.ts 提供节点尺寸变化观测。

3.10 屏幕事件(窗口尺寸变化)

screen_events.ts 提供「页面显示区域尺寸变化」事件,对齐小程序语义(基础库 ≥ 2.4.0)。

完整设计(链路/分层/边界/多 scope 隔离/验证)见 docs/design/screen-events.md。

示例:

// 页面(根组件)自身回调
Page({
  onResize(res) {
    res.size.windowWidth  // 新的显示区域宽度
    res.size.windowHeight // 新的显示区域高度
  },
})
// 自定义组件:页面尺寸变化时整棵组件树收到 resize
Component({
  pageLifetimes: {
    resize(res) { /* res.size.windowWidth / windowHeight */ },
  },
})

事件来源:

  • 引擎卡片链路(OHOS/Android FlexView):原生容器尺寸变化 → updateDimension → Dimensions.set(携带 __rootId__)→ NativeBackendContext.setWindowSize(按 rootId 路由 + 真实宽高变化检测)→ 变化时经 __GLOBAL__.__flexuiScreenResizeListeners 广播(白名单通道,同 Dimensions/colorMode 监听器模式);
  • 其它宿主(浏览器预览/测试):直接调用 notifyScreenResize(rootId, width, height)。

分发:页面根组件(Root)构造时注册(registerRootForScreenResize,按 backend duck-typing 的 rootViewId 精确路由,卡片 A 的容器变化不会误触发卡片 B):

  1. 页面根组件顶层 onResize(Page 定义顶层函数字段注册为组件方法,未声明则 no-op);
  2. 整棵页面树的 pageLifetimes.resize(triggerPageLifetime('resize', [res]) 递归 含根组件自身与全部自定义组件)。

回调异常遵循框架规则:onResize 调用捕获后 dispatchError 上报(不 rethrow), pageLifetimes.resize 由 FuncArr safeCallback 兜底。事件载荷与 selectViewport() 同源(均取 backend 的权威窗口尺寸)。

3.10 Harmony 适配

harmony/ 目录提供 HarmonyOS 平台的特化适配。


4. 与 @flexui/core 的关系

@flexui/ascf 作为 @flexui/core 的 peerDependency 存在,它不重复实现核心功能,而是:

  1. 接口翻译:将 MiniProgram 风格的 API 映射到 FlexUI Core API
  2. 约定增强:提供 ASCF 生态特有的组件、约定和开发模式
  3. 构建集成:与 webpack 插件配合,实现 HXML/CSS 的编译

5. 构建集成

5.1 配合 webpack 插件

// webpack.config.js
const { FlexUIAscfWebpackPlugin } = require('flexui-webpack-plugin')

module.exports = {
  plugins: [
    new FlexUIAscfWebpackPlugin({ path: './src' })
  ],
  module: {
    rules: [
      { test: /\.hxml$/, use: 'flexui-webpack-plugin/hxml_loader' },
      { test: /\.css$/, use: 'flexui-webpack-plugin/css_loader' },
    ]
  }
}

5.2 包的分离导出

@flexui/ascf             → 核心适配器 API
@flexui/ascf/components  → 内置组件导出

6. 类型定义

types.ts 定义了 ASCF 适配层使用的关键类型,包括组件选项、HXML 相关类型、运行时环境类型等。


7. 设计决策

7.1 为什么不直接在 @flexui/core 中实现 ASCF 兼容?

  • 关注点分离:核心框架保持纯净,不依赖任何特定生态
  • 可替换性:其他适配器 (如 React/Vue 适配) 可以独立开发
  • 体积控制:不需要 ASCF 兼容的应用不必加载这层

7.2 为什么使用 peerDependency?

@flexui/ascf 声明 @flexui/core 为 peerDependency,确保:

  • 应用可以控制核心框架的版本
  • 避免多个 core 实例共存导致的状态不一致

7.3 组件导出策略

内置组件通过 @flexui/ascf/components 子路径独立导出:

  • 需要内置组件时显式导入,不增加基础包体积
  • Tree-shaking 友好,未使用的组件不会被打包