Skip to content
On this page

响应式变量与实时文字 ​

响应式变量是 ChaUI 最值得优先掌握的能力之一。页面不需要反复执行“找到文本,再把内容改成新字符串”的脚本;只要让文字、布局或条件引用变量,变量变化后,界面就会自动使用最新结果重新显示。

它适合制作生命值、余额、倒计时、任务进度、选择状态、分页数字和实时提示等动态界面。

一个最直观的例子 ​

先在页面默认变量中准备计数:

yaml
vars:
  count: 0 # 页面刚打开时从 0 开始

然后让文本内容引用它:

yaml
text:
  value: "已经点击 {vars.count} 次"

按钮脚本只负责修改变量:

text
vars.count = vars.count + 1

每次点击后,页面都会立即显示新的次数。文本组件不需要额外的修改文字脚本。

页面生命周期同样可以驱动响应式刷新。events.open、组件 events.create 或自定义方法修改变量后,文字、布局、显隐条件和按钮选中状态会在接下来的渲染中使用最新值;不需要手动刷新页面。

yaml
events:
  open: 方法.初始化()
methods:
  初始化: |-
    vars.title = "欢迎回来"
    vars.ready = true

花括号中的内容才会计算 ​

text.value 和 button.label 只有 {...} 内的内容会作为表达式读取,花括号外的文字保持原样。

text
玩家生命:{vals.player.health} / {vals.player.maxHealth}
任务进度:{vars.current} / {vars.total}
完成比例:{vars.current / vars.total * 100}%

可以在同一段文字中放入多个表达式,也可以使用四则运算、括号和数学函数:

text
剩余生命:{vals.player.maxHealth - vals.player.health}
面板数值:{(vars.base + vars.extra) * 2}

数字结果会自动去掉没有意义的末尾小数,例如 10.0 会显示为 10。

输出普通花括号 ​

如果内容本身需要显示花括号,使用双花括号:

写成“两个连续的左花括号 + vars.count + 两个连续的右花括号”时,页面会显示普通的 {vars.count},不会读取变量。

两个连续的左花括号输出一个左花括号,两个连续的右花括号输出一个右花括号。

常用值从哪里来 ​

页面变量 vars ​

页面变量属于当前打开的页面会话,可以由默认配置、组件脚本或服务端业务更新。

yaml
vars:
  playerName: "旅行者"
  count: 0
  ready: false
text
欢迎回来,{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 ​

玩家常量来自当前客户端玩家状态,只能读取,不能由脚本赋值。最常见的写法如下:

text
生命:{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 缩放坐标,并会随鼠标移动和按键状态实时更新。例如:

text
鼠标:{vals.mouse.x}, {vals.mouse.y} 左键:{vals.mouse.leftDown}

左右中键状态和全部中文写法见只读常量。

PAPI 常量 vals.papi ​

PAPI 常量由服务端 PlaceholderAPI 解析,再以只读常量提供给页面。客户端不需要安装占位符扩展,也不会自行解析 %placeholder%。

下面是一份完整页面示例:

yaml
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 就足够;只有确实需要快速变化的内容才应缩短间隔。

不只文字会响应 ​

同一份变量还可以同时驱动布局、显示条件和按钮文字:

yaml
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(...):

yaml
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 后通过页面打开指令打开它:

yaml
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 常量或不完整表达式不会让页面崩溃,而是保留原占位内容:

text
余额:{vals.papi.unknown}
错误公式:{vars.count + }

如果游戏中仍看到花括号内容,请依次检查变量名、PAPI 映射名、表达式拼写和服务端 PlaceholderAPI 扩展是否可用。

推荐实践 ​

  1. 当前页面状态放进 vars;需要全服共享的值在服务端 globals 声明,页面通过 vals.global 读取。
  2. 玩家状态使用 vals.player,跟随目标状态使用 vals.boundEntity,PlaceholderAPI 结果使用 vals.papi。
  3. 需要自动显隐时使用 visibleWhen,不要每帧执行脚本。
  4. PAPI 映射使用清楚的短名称,例如 balance、rank、questProgress。
  5. 对外展示的数字可以在表达式中运算,但复杂业务结果更适合先由服务端变量计算完成。

继续阅读语法与事件,可以学习如何用分号在单行输入框中组合多条脚本。