响应式变量与实时文字
响应式变量是 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.global
需要所有玩家看到同一个主题、公告或活动状态时,在 global-scripts.yml 的 globals 中声明变量,再让页面读取 {vals.global.theme} 或 {常量.全局.theme}。服务端修改后,已经打开的页面会自动更新;页面只能读取,不能赋值。配置、修改方法与 reload 规则见全局变量。
世界页面绑定实体 vals.boundEntity
跟随页面可以用 {vals.boundEntity.name} 显示目标名称,用 {vals.boundEntity.health}/{vals.boundEntity.maxHealth} 显示生命值。这里读取的是当前绑定目标,和观看页面的玩家状态 vals.player 不同。完整配置、打开指令与目标暂时消失时的行为见世界页面实体跟随。
玩家常量 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 - self.width) / 2
y: 30
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
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,右侧只会在点击时计算一次并保存为固定数字。
图片路径也可以引用变量
图片和按钮等支持响应式素材路径的字段可以填写 gui/{vars.theme}/panel.png。变量变化后会重新选择素材,无需关闭页面。
先在客户端 resourcepacks/ChaUI/ 中准备 gui/blue/panel.png 与 gui/red/panel.png,再把下面完整页面保存为 pages/theme_path_demo.yml,执行 /chaui reload 后通过页面打开指令打开它:
id: theme_path_demo
version: 1
title: 动态路径示例
size:
width: 240
height: 100
coordinateMode: absolute
display:
mode: screen
screen:
dimBackground: true
vars:
theme: blue # 仅当前页面的主题
events: {}
methods: {}
elements:
- id: theme_image
type: image
layout:
x: 10
y: 10
width: 80
height: 80
image:
path: "gui/{vars.theme}/panel.png"
- id: switch_theme
type: button
layout:
x: 110
y: 40
width: 110
height: 24
button:
label: "当前:{vars.theme}"
events:
leftClick: |
if vars.theme == "blue" {
vars.theme = "red"
} else {
vars.theme = "blue"
}每次点击按钮,图片都会在两套素材之间切换。希望全服共享主题时,将图片路径改为 gui/{vals.global.theme}/panel.png,同时在服务端声明并修改全局 theme;页面按钮不能直接给 vals.global.theme 赋值,应调用已配置的通用方法,完整示例见全局变量。
变量替换后的路径仍需满足对应字段的素材规则:本地路径使用 /,不能包含盘符、反斜杠或 ..,目标文件必须存在。GIF 可以用于支持动画的素材字段;更换路径会重新开始播放。不能据此把 {vars.*} 写进 item_display.itemId 等不支持模板的字段,动态物品请使用物品展示 API。
无效表达式如何处理
未知变量、缺失 PAPI 常量或不完整表达式不会让页面崩溃,而是保留原占位内容:
余额:{vals.papi.unknown}
错误公式:{vars.count + }如果游戏中仍看到花括号内容,请依次检查变量名、PAPI 映射名、表达式拼写和服务端 PlaceholderAPI 扩展是否可用。
推荐实践
- 当前页面状态放进
vars;需要全服共享的值在服务端globals声明,页面通过vals.global读取。 - 玩家状态使用
vals.player,跟随目标状态使用vals.boundEntity,PlaceholderAPI 结果使用vals.papi。 - 需要自动显隐时使用
visibleWhen,不要每帧执行脚本。 - PAPI 映射使用清楚的短名称,例如
balance、rank、questProgress。 - 对外展示的数字可以在表达式中运算,但复杂业务结果更适合先由服务端变量计算完成。
继续阅读语法与事件,可以学习如何用分号在单行输入框中组合多条脚本。
猹件开发组