前三期聊了选型、对比、跑 demo。如果你跟着上一期把counter跑起来了窗口弹出来那一瞬间应该还挺爽的。然后你打开src/main.rs往下翻了几行。不是熟悉的 Rust 结构体不是fn main()而是一堆看起来像 CSS 又像 JSON、但两边都不像的东西。我当时是半夜看的盯着屏幕愣了大概两分钟。然后去搜教程。更懵了。有的文章在讲live_design!有的在讲script_mod!还有在讲 Splash 的。我花了一整个晚上才搞明白它们之间的关系。这一期就是想帮你省掉那个晚上。先交底这篇不是 Splash 语法大全也不是官方文档翻译。它就是一份第一次打开 Makepad 代码时先看懂哪几块就够了的导航。1. 先别读代码先搞清楚一个时间线很多人卡在这一步问题不在代码本身而在于看了不同时代的资料。Makepad 的 UI 描述方式经历过一次比较大的转向老版本用live_design!宏写 UI语法混在 Rust 宏里当前版本Makepad 2.0 / dev 分支用script_mod! SplashUI 描述变成了一套独立的 DSL这不是旧语法换了几个关键字那种小改。是整个 UI 描述层的组织思路变了。所以你搜到 2023 年的教程全是live_design! { ... }而官方dev分支打开全是script_mod!和 Splash。你没看错它们就是同一个框架在两个时间点的样子。这个时间差不说清楚新手大概率会越搜越乱。截至2026 年 6 月官方dev分支的示例已经全面偏向script_mod!/ Splash。这一篇也按新写法来。2. 第一层UI 声明 —— 界面长什么样先解决最让人困惑的问题在 Makepad 里一个界面到底是怎么被描述出来的。2.1 一个最小示例以官方counter为参考简化后大概长这样script_mod!(modmy_app{main_window:Window{window.inner_size:vec2(420,220)body:{View{width:Fill,height:Fill,flow:Down,align:CenterLabel{text:Count: 0}Button{text:Increment}}}}});我第一次看到这段代码脑子里有两个问号script_mod!是啥这算 Rust 代码吗main_window : Window { ... }这:又是什么语法2.2 先别管script_mod!script_mod!是个宏编译时 Makepad 会把里面的 DSL 展开成框架能理解的东西。第一次读别追宏展开。追了就出不来了。你只需要先抓住一件事这段代码定义了一个窗口窗口里有一个垂直排列的视图视图里放了一个标签和一个按钮。够了。2.3:和:记两个词就行这两个符号是 Makepad DSL 里出现频率最高的也是新手最容易懵的main_window : Window { ... }声明一个叫main_window的东西类型是Windowbody : { ... }往body里面追加内容粗暴理解:→ “我声明一个”:→ “往里面塞”不严谨。但够用。第一遍读不卡住就是胜利。2.4 先认控件名别的往后放读 Makepad UI 代码最省力的办法先找你认识的单词忽略不认识的语法。上面那段代码你盯住这四个词就行Window— 窗口View— 容器Label— 文本Button— 按钮这四个认出来界面的骨架已经在你脑子里了。vec2(420, 220)、Fill、Down第二轮再看别急。3. 第二层布局和样式 —— 东西怎么摆知道有什么了下一步这些东西为什么摆在那个位置。3.1 flow 管方向flow是 Makepad 里用得最多的布局属性。没有之一。View { flow: Down, // 从上往下排 // flow: Right, // 从左往右排 }Down是垂直Right是水平。和 CSS 的flex-direction: column / row一个意思只是名字更短。3.2 align 管对齐View { flow: Down, align: Center, }align管的是子元素在排列方向上的对齐。Center、Start、End三个值够用了。3.3 width / height 管尺寸View { width: Fill, // 撑满 height: 200, // 固定 200 } Button { width: Fit, // 自适应内容 }Fill撑满Fit自适应具体数字就是固定尺寸。flowalignwidth/height三个属性组合起来常见布局基本都能出来。3.4 样式直接写在控件上这一点和 CSS 差别很大。Makepad 没有单独的样式表颜色、字体、间距全写在控件上Label { text: Hello draw_text: { color: #333333, font_size: 16.0 } }我第一次看到这种写法第一反应是这也太不分离了吧。但用了两天之后发现看一个控件就能看到它的全部外观不用去另一个文件翻 class。说实话小项目里挺爽的。4. 第三层事件和逻辑 —— 点了为什么有反应界面能看了布局能摆了。最后一步点了按钮为什么会有反应。4.1 UI 描述和 Rust 逻辑在同一个script_mod!里但角色分开script_mod!(modmy_app{// 第一部分UI 描述DSLmain_window:Window{...}// 第二部分Rust 逻辑#[run]fnmain()-Result(),String{// 初始化}#[event]fnhandle_button_click(mutself,cx:mutCx,actions:Actions){// 事件处理}});UI 描述只管长什么样Rust 逻辑管点完发生什么。它们写在一个宏里但分工很明确。4.2 按钮点击是怎么接上的以 counter 的点击为例简化后大概是这样// UI 侧给按钮一个 idButton{id:increment_button,text:Increment}// Rust 侧通过 id 找到按钮判断是否被点击ifself.ui.button(cx,ids!(increment_button)).clicked(actions){self.count1;self.ui.label(cx,ids!(count_label)).set_text(cx,format!(Count: {},self.count));self.ui.redraw(cx);}整个连接靠的就是id。UI 里给控件起个名字id: increment_buttonRust 里通过同一个名字找到它ids!(increment_button)然后判断事件、更新状态、触发重绘。所以我读 Makepad 代码有个习惯先扫一遍 UI 描述把所有id圈出来。这些id就是 UI 和逻辑之间的接头暗号找到它们后面的关系网就清楚了。4.3 状态放哪Makepad 里状态直接挂在script_mod!模块里script_mod!(modmy_app{count:i320,name:StringString::new(),main_window:Window{...}#[event]fnhandle_click(mutself,cx:mutCx,actions:Actions){// self.count, self.name 直接用}});不需要单独的 store不需要 context。字段就挂在模块上self.xxx直接访问。中小型应用里这个模型用起来很快。5. 一条偷懒的阅读顺序如果现在你打开一个 Makepad 示例不知道从哪开始看按这个顺序来先找main_window— 界面入口往下追认控件名—Window、View、Label、Button……先在脑子里画个树看flow和align— 搞清楚东西为什么在这个位置找所有id— 有id的控件说明 Rust 那边会用到它顺着id跳到 Rust— 看事件处理、状态更新这个顺序走一遍大部分示例就不会再给人一堆符号看不懂的感觉了。6. 我踩过的两个坑6.1 拿 CSS 心智硬套Makepad 的 DSL 和 CSS 有几个词长得像width、align但布局模型完全不是 Flexbox。没有display: flexflow就是排列方式没有margin/padding的完整对应样式不级联父元素不影响子元素我当时卡在这上面至少两个小时一直在找Makepad 的 padding 怎么写。后来发现有些东西它就是没有。接受这是一套新东西比纠结为什么和 CSS 不一样快得多。6.2 一上来就想搞懂宏展开script_mod!展开之后代码量很大充满框架内部细节。第一次读把它当黑盒。先理解里面的 DSL 结构和 Rust 逻辑怎么组织。等你整个框架有感觉了回头看宏展开那个时机才对。7. 和上一期的关系从第三期直接过来的话第三期把窗口跑起来按钮能点这一期看懂这些按钮和文字是怎么被定义、怎么被摆放、怎么连上逻辑的两期合在一起你就能从能跑走到能读。总结这一期其实就一件事帮你建立 Makepad UI 代码的阅读框架。认控件名 → 看 flow/align → 顺 id 找逻辑。这个顺序抓住大部分代码就不会再让你愣在那了。下一期拆事件处理、状态管理和组件通信。从能看的界面到能交互的应用。你第一次打开 Makepad 代码卡在哪一步评论区聊聊。我猜很多人的答案都差不多。