响应式变量与实时文字
响应式变量是 ChaUI 最值得优先掌握的能力之一。页面不需要反复执行“找到文本,再把内容改成新字符串”的脚本;只要让文字、布局或条件引用变量,变量变化后,界面就会自动使用最新结果重新显示。
它适合制作生命值、余额、倒计时、任务进度、选择状态、分页数字和实时提示等动态界面。
一个最直观的例子
先在页面默认变量中准备计数:
vars:
count: 0 # 页面刚打开时从 0 开始然后让文本内容引用它:
text:
value: "已经点击 {vars.count} 次"按钮脚本只负责修改变量:
vars.count = vars.count + 1每次点击后,页面都会立即显示新的次数。文本组件不需要额外的修改文字脚本。
页面生命周期同样可以驱动响应式刷新。events.open、组件 events.create 或自定义方法修改变量后,文字、布局、显隐条件和按钮选中状态会在接下来的渲染中使用最新值;不需要手动刷新页面。
events:
open: 方法.初始化()
methods:
初始化: |-
vars.title = "欢迎回来"
vars.ready = true花括号中的内容才会计算
text.value 和 button.label 只有 {...} 内的内容会作为表达式读取,花括号外的文字保持原样。
玩家生命:{vals.player.health} / {vals.player.maxHealth}
任务进度:{vars.current} / {vars.total}
完成比例:{vars.current / vars.total * 100}%可以在同一段文字中放入多个表达式,也可以使用四则运算、括号和数学函数:
剩余生命:{vals.player.maxHealth - vals.player.health}
面板数值:{(vars.base + vars.extra) * 2}数字结果会自动去掉没有意义的末尾小数,例如 10.0 会显示为 10。
输出普通花括号
如果内容本身需要显示花括号,使用双花括号:
写成“两个连续的左花括号 + vars.count + 两个连续的右花括号”时,页面会显示普通的 {vars.count},不会读取变量。
两个连续的左花括号输出一个左花括号,两个连续的右花括号输出一个右花括号。
三类常用值
页面变量 vars
页面变量属于当前打开的页面会话,可以由默认配置、组件脚本或服务端业务更新。
vars:
playerName: "旅行者"
count: 0
ready: false欢迎回来,{vars.playerName}
点击次数:{vars.count}
是否准备:{vars.ready}中文前缀也可以写成 变量,例如 {变量.count}。
玩家常量 vals.player
玩家常量来自当前客户端玩家状态,只能读取,不能由脚本赋值。最常见的写法如下:
生命:{vals.player.health} / {vals.player.maxHealth}
护甲:{vals.player.armor} 等级:{vals.player.experienceLevel}
主手:{vals.player.inventory.mainhand.id} × {vals.player.inventory.mainhand.count}玩家基础状态、36 格背包汇总、主手、副手和全部盔甲字段及中文别名,请查阅只读常量。需要直接显示和操作真实背包槽位时,再查阅背包映射表。
鼠标常量 vals.mouse
鼠标常量使用 Minecraft GUI 缩放坐标,并会随鼠标移动和按键状态实时更新。例如:
鼠标:{vals.mouse.x}, {vals.mouse.y} 左键:{vals.mouse.leftDown}左右中键状态和全部中文写法见只读常量。
PAPI 常量 vals.papi
PAPI 常量由服务端 PlaceholderAPI 解析,再以只读常量提供给页面。客户端不需要安装占位符扩展,也不会自行解析 %placeholder%。
下面是一份完整页面示例:
id: player_status
version: 1
title: 玩家状态
size:
width: window.width
height: window.height
coordinateMode: absolute
display:
mode: screen
screen:
dimBackground: true
vars:
title: "角色信息" # 普通页面默认变量
papi:
refreshTicks: 20 # 每 20 tick 刷新一次;允许 5 至 1200,默认 20
values:
balance: "%vault_eco_balance%" # 页面中使用 vals.papi.balance
prefix: "%luckperms_prefix%" # 页面中使用 vals.papi.prefix
elements:
- id: status_text
type: text
parent: ""
visible: true
enabled: false
pointerEvents: pass
scale: 1
opacity: 1
z: 10
layout:
x: window.width * 0.5 - 100
y: 30
width: 200
height: 36
text:
value: "{vars.title}\n称号:{vals.papi.prefix}\n余额:{vals.papi.balance}"
font: ""
color: "#FFFFFF"
textSize: 1
textLineLength: 0
revealIntervalMs: 0
align: center
tooltip: []
events: {}values 左侧是页面内使用的安全名称,右侧是 PlaceholderAPI 模板。名称 balance 会映射为 {vals.papi.balance}。
PAPI 常量名称可以使用字母、数字、下划线和 Unicode 字符,但不能以数字开头。一个页面最多配置 64 项。
刷新与共享
- 页面打开后会立即取得一次 PAPI 常量,不必等待第一个刷新周期。
refreshTicks控制刷新频率,默认20,约为一秒一次。- 值没有变化时,页面会继续显示当前结果,不会产生可见闪烁。
- 同一玩家同时打开同一个页面的多个实例时,会共享该页面的 PAPI 刷新结果。
- 页面不再使用后,相关刷新会停止;重新打开时重新取得最新值。
- 服务端没有安装 PlaceholderAPI 时,ChaUI 其他页面仍可正常使用;未取得的表达式会保留原占位内容,方便发现配置问题。
不要为了追求“更实时”盲目把刷新间隔设为 5。余额、称号等变化较慢的内容通常使用 20 至 100 就足够;只有确实需要快速变化的内容才应缩短间隔。
不只文字会响应
同一份变量还可以同时驱动布局、显示条件和按钮文字:
vars:
progress: 0.35
ready: false
elements:
- id: progress_text
type: text
visibleWhen: "vars.progress > 0"
layout:
x: 20
y: 20
width: 160
height: 16
text:
value: "进度:{vars.progress * 100}%"
- id: confirm_button
type: button
enabledWhen: "vars.ready == true"
layout:
x: 20
y: 45
width: 100
height: 20
button:
label: "当前进度 {vars.progress * 100}%"服务端或脚本修改 progress 后,文字、按钮标签和引用该变量的布局会在同一页面状态下更新。这就是响应式页面的核心价值:只维护数据,界面自动跟随数据变化。
页面 yml 中直接填写的布局公式本身就是响应式的。若公式由点击事件或方法在运行时写入,需要显式使用 formula(...):
events:
leftClick: |-
component("progress_text").layout.x = formula(
component("progress_bar").layout.x + component("progress_bar").layout.width + 4
)如果去掉 formula,右侧只会在点击时计算一次并保存为固定数字。
无效表达式如何处理
未知变量、缺失 PAPI 常量或不完整表达式不会让页面崩溃,而是保留原占位内容:
余额:{vals.papi.unknown}
错误公式:{vars.count + }如果游戏中仍看到花括号内容,请依次检查变量名、PAPI 映射名、表达式拼写和服务端 PlaceholderAPI 扩展是否可用。
推荐实践
- 页面状态统一放进
vars,文字只负责展示。 - 玩家本地状态使用
vals.player,服务端插件变量使用vals.papi。 - 需要自动显隐时使用
visibleWhen,不要每帧执行脚本。 - PAPI 映射使用清楚的短名称,例如
balance、rank、questProgress。 - 对外展示的数字可以在表达式中运算,但复杂业务结果更适合先由服务端变量计算完成。
继续阅读语法与事件,可以学习如何用分号在单行输入框中组合多条脚本。
猹件开发组