Skip to content
On this page

语法与事件

ChaUI Script 使用接近 JavaScript 的简洁写法,但它不是完整的 JavaScript。页面只接受 ChaUI 明确支持的赋值、条件和内置动作,无法识别的语句会被安全跳过,不会允许任意客户端代码运行。

基本规则

  • 换行和结构外的分号都可以分隔语句。
  • 字符串可以使用双引号或单引号。
  • 数字可以是整数或小数,布尔值使用 truefalse
  • 函数参数使用逗号分隔。
  • 条件分支使用 if condition { ... } else { ... }
  • 有界循环使用 repeat(count) { ... },周期任务使用强制命名的 timer("name", ticks) { ... }
  • component("id") 返回当前页面会话中的安全组件对象,可以继续读取 .parent.layout 和对应类型的数据块。
  • 给布局属性使用普通 = 时保存当前计算结果;使用 formula(...) 时保存会持续重新计算的公式。
  • 取整、保留小数、限制范围、插值、三角函数和随机数见数学函数
  • 组件 ID 建议只使用英文字母、数字、下划线和连字符。
text
vars.count = 1
vars.message = "欢迎回来"
vars.ready = true
component("title").visible = false
sound("sounds/click.ogg")

编辑器脚本输入框适合使用分号在一行中组合多个动作:

text
vars.count = vars.count + 1; component("counter").visible = true; sound("sounds/click.ogg")

字符串内部的分号不会被切开:

text
vars.message = "第一段;第二段"; packet("dialog:reply", vars.message)

事件触发名

编辑器字段含义常见用途
leftPress / rightPress / middlePress对应按键在当前组件上按下时立即触发按压动画、开始拖动、播放按下音效
leftRelease / rightRelease / middleRelease按下捕获仍有效时,松开对应按键触发恢复缩放、结束拖动、停止持续状态
leftClick / rightClick / middleClick在同一组件上完成按下和松开后触发确认、关闭、业务操作
hoverEnter指针第一次进入组件范围时触发悬浮说明、路径切换、音效提示
hoverLeave指针离开组件范围时触发恢复默认图片或隐藏提示
create当前组件实例创建时触发一次初始化组件状态、动态复制后的设置

hoverEnter 不会在鼠标停留期间每帧重复运行;离开后再次进入,才会再次触发。

一次完整左键操作的顺序是 leftPress → leftRelease → leftClick。如果按下后把鼠标移到别处再松开,原组件可以收到 leftRelease,但不会收到 leftClick。组件在期间被隐藏、删除或禁用时,捕获会清理,不再继续触发。

按钮的选中变量、输入框焦点和物品槽交换都发生在有效的左键 Click 阶段。PressRelease 只执行各自脚本,不会提前完成点击行为。

唯一目标与防穿透

ChaUI 会从最前面的组件向后查找,每次只选一个组件作为当前目标。普通页面、世界页面和编辑器预览使用同一套规则,因此预览中验证通过的遮挡关系不会在实际打开后改变。

  • pointerEvents: auto:交互组件天然命中;普通展示组件只有配置事件或提示时才命中。
  • pointerEvents: block:无论有没有事件,都挡住后方组件。
  • pointerEvents: pass:完全忽略该组件,让指针继续寻找后方目标。
  • visible: false:不显示也不遮挡。
  • enabled: false:不执行自身行为,但仍然遮挡。

下面是一份可以直接复制的按钮配置。按下时缩小,松开时恢复,只有完整点击才执行确认动作:

yaml
vars:
  confirmScale: 1

elements:
  - id: confirm_button
    type: button
    parent: ""
    visible: true
    enabled: true
    pointerEvents: auto
    scale: vars.confirmScale
    opacity: 1
    z: 20
    layout:
      x: window.width * 0.5 - 45
      y: window.height * 0.5 - 12
      width: 90
      height: 24
    button:
      label: "确认"
      path: gui/default/confirm.png
      hoverPath: gui/default/confirm_hover.png
    events:
      leftPress: |-
        vars.confirmScale = 0.96
      leftRelease: |-
        vars.confirmScale = 1
      leftClick: |-
        log("确认完成")

执行结果:鼠标按下时按钮围绕中心缩小;松开后恢复。只有按下和松开都落在同一个按钮上,聊天栏才会出现“确认完成”。

页面根级还支持 events.openevents.closeevents.key.<按键名>events.mouse.*。页面打开先执行 open,再按顺序执行所有初始组件的 create;普通关闭和 reload 关闭旧页面都会执行 close。键盘、鼠标和滚轮事件的配置表与示例见页面组件,完整按键名称和键盘 ID 见键盘对照表

方法调用

页面根级 methods 中的脚本使用零参数调用:

text
methods.refresh()
方法.刷新()

方法共享当前页面变量和组件状态,可以互相调用,但不能递归,也不接收参数或返回值。

字符串与参数

函数参数中的逗号和引号需要保留在字符串内。需要在双引号字符串中写入双引号时,可以使用反斜杠转义。

text
vars.message = "他说:\"欢迎回来\""
packet("dialog:reply", "同意,并继续", "第二项数据")

复杂数据可以先整理为 JSON 字符串,再作为自定义包的一项数据发送:

text
packet("shop:select", "{\"item\":\"example\",\"amount\":2}")

packet() 可以写在任何真实运行时会执行的事件、方法或计时器脚本中,不要求必须是点击事件。方法和计时器继承创建它们的原始页面或组件上下文;编辑器编辑状态与隔离预览不会发送。

条件分支

条件成立时执行 if 内的语句,否则执行 else。不需要其他分支时可以省略 else

text
if vars.confirmed == true {
  component("status").text.value = "已经确认"
  component("confirm_button").enabled = false
} else {
  component("status").text.value = "请先确认"
}

中文别名同样可以用于条件和动作:

text
if 变量.confirmed == true {
  组件("status").文本.内容 = "已经确认"
} else {
  组件("status").文本.内容 = "请先确认"
}

多步事件示例

下面的按钮会在第一次点击时显示详情区,再次点击时隐藏详情区。

yaml
vars:
  detailsOpen: false # 记录当前详情区是否打开

elements:
  - id: toggle_button
    type: button
    layout:
      x: 20
      y: 20
      width: 100
      height: 20
    button:
      label: "展开或收起"
    events:
      leftClick: |
        if vars.detailsOpen == true {
          vars.detailsOpen = false
          component("details").visible = false
        } else {
          vars.detailsOpen = true
          component("details").visible = true
        }

动作使用函数写法

页面动作统一使用 close()open("detail_page")sound("sounds/click.ogg") 这类函数写法。函数参数、字符串转义、条件块与分号组合都使用同一套规则,方便页面继续扩展。

函数参数是文字时要放在引号中;无参数动作也必须保留括号。例如关闭当前页面写 close(),打开另一页面写 open("detail_page")

继续阅读变量与条件,可以了解页面变量、玩家状态和动态公式;循环与计时器则介绍 repeat、命名 timer 和页面关闭时的自动清理。