跳转至

02 · 核心概念

FlowUI 用三句话就能说明白。学完本页,后面各章都是在展开这三句话。

三句话

  1. Model + 消息 + Update 管业务数据;View 只读 Model,用 send 表达意图。
  2. Style 管这个盒子的尺寸与外观;布局容器 管孩子们怎么排列。
  3. Key 管跨帧身份;固定布局可使用自动 Key,动态内容需要稳定的业务 Key 或作用域。

副作用(网络、定时器、文件)用 Cmd / Subscription,不要在 View 里改 Model。

数据流

用户点击 / 键盘 / 订阅
        │
        ▼
     send(Msg)
        │
        ▼
     Update(*Model, Msg)   ← 唯一改 Model 的地方
        │
        ├── 可选返回 Cmd(异步副作用)
        ▼
     View(ctx, Model, send) → Widget 树
        │
        ▼
     布局 · 绘制 · 交互

职责边界

放这里 不放这里
Model:业务字段、表单值、列表数据 指针点击态、动画进度
Update:根据 Msg 改 Model 直接画 UI、阻塞网络
View:读 Model,声明控件树 改 Model、开 goroutine 改状态
Context:主题快照、焦点、交互槽 业务数据
Style:宽高、padding、颜色、阴影 flex 增长、兄弟间距(容器负责)
Key:跨帧保留 clickable / 动画 用渲染顺序当身份

术语表

术语 含义
MVU Model-View-Update;消息驱动
Widget 可布局节点;实现 Layout(ctx, gtx)
Send 把消息投进队列,下一帧由 Update 处理
Cmd Update 返回的异步命令;独立 goroutine 执行
Subscription 按 Model 声明的长生命周期输入(定时器、流)
Style 不可变的外观/盒模型声明;fluent 链式配置
On / Rules 按交互/语义状态叠样式(Hover、Pressed…)
Part 复合控件内部零件(Track、Thumb、Label…)
Key 跨帧身份;固定布局可自动生成,动态内容使用业务身份
Host 统一单盒外壳绘制;Box / layout.InteractiveResolved
受控 / 非受控 值或 open 是否由 Model 持有
Action 菜单/快捷键配方;与异步 Cmd 不是一回事

构造函数与类型名

主构造函数统一使用 New,类型使用 Widget,两者在 Go 命名空间中互不冲突:

btn := button.New("保存") // 构造函数直接接收文本
// 类型是 button.Widget,方法在类型上:
btn = btn.Variant(button.Primary).OnClick(func() { ... })

go doc / IDE 补全看 button.Widget、input.Widget 等方法集。

自动 Key 与显式 Key

button.New、input.New 等构造函数为固定布局提供自动身份:

button.New("保存")
input.New(m.Email)

自动身份由组件类型、构造位置、所在 Key 作用域,以及同位置组件在本帧首次解析 Key 的顺序决定。每个窗口独立计数;提前创建组件和每帧重新创建组件遵循相同规则。显示文本不参与身份判断。

动态列表、共用构造辅助函数的条件性兄弟组件,以及会改变位置的组件,应显式设置业务 Key:

input.New(item.Name).Key(item.ID)

重复的整个子树可使用 layout.Key(item.ID, child) 建立稳定作用域。普通 Row、Column 不会自动建立 Key 作用域。table.New 等直接接收 Key 的构造函数使用调用者传入的身份。

没有构造标记的底层交互原语,在收到空 Key 时按状态类型和作用域内顺序生成回退身份。它适用于位置稳定的内部结构,不能替代业务身份。

改变显式 Key 会建立新的交互身份;同一作用域内两个组件复用同一个 Key 属于错误。Key 是运行时身份,不用于持久化。自动标记格式属于内部实现,应用 Key 不应使用其保留的零字节分隔标记 \x00@。

Context 是什么

*ui.Context 是每个窗口的帧与交互服务,不是第二个 Model:

  • 可读:Theme()、Language()、WindowState()
  • 焦点:RequestFocus、FocusVisible
  • 自定义控件:UseState(仅瞬态交互,不是业务状态)

业务字段请放进你的 Model。

与 Gio 的关系

FlowUI 建立在 Gio 之上。日常应用只需 ui 包;路径 C 画布自绘时才会直接接触 Gio 的 layout / op。 产品 API 不按 Gio 细节组织,按 MVU + Style + 布局来学即可。

下一步