Skip to content
On this page

页面生命周期与自定义方法

ChaUI 页面可以在打开、组件创建和关闭时自动执行脚本。配合自定义方法,你可以把初始化、刷新和收尾逻辑集中写在页面根部,再从不同事件中调用,避免同一段脚本散落在多个组件里。

三类生命周期事件

配置位置事件触发时机
页面根级 events.open页面打开新页面作用域建立后最先执行
组件 events.create组件创建open 之后按页面组件顺序执行;脚本新增或复制的组件也会执行一次
页面根级 events.close页面关闭普通关闭、HUD/世界实例关闭和 reload 更换旧页面时执行

一次正常打开的固定顺序是:页面 open → 每个初始组件的 create。同一个组件对象只执行一次 create;删除后重新创建的同 ID 组件属于新对象,会再次触发。

执行 open 前,当前页面会话的组件对象树和父子引用已经建立,因此初始化方法可以直接读取组件、父布局和原始公式,也可以安全建立跨组件布局公式。

yaml
vars:
  opened: false
  title: "准备中"

events:
  open: |-
    方法.初始化()
  close: |-
    vars.opened = false

methods:
  初始化: |-
    vars.opened = true
    vars.title = "页面已经就绪"

elements:
  - id: title
    type: text
    layout:
      x: 20
      y: 20
      width: 180
      height: 20
    text:
      value: "{vars.title}"
    events:
      create: vars.title = "标题组件已创建"

自定义方法

页面根级 methods 使用“方法名: 脚本”保存可复用逻辑。方法不接收参数,也不返回结果,但会直接共享当前页面的 vars、组件临时状态和只读常量。

yaml
methods:
  refresh: |-
    vars.count = vars.count + 1
    component("status").visible = true
    component("status").layout.x = formula(component("panel").layout.x + 8)

英文调用:

text
methods.refresh()

中文调用:

text
方法.refresh()

方法可以继续调用其他方法。ChaUI 会拒绝未知方法、直接递归和间接递归;调用展开最多 16 层,一次同步事件最多执行 4096 个脚本节点。方法也不能用来绕过 repeattimer 中禁止批量执行高权限动作的限制。

动态组件的 create

addComponentcopyComponent 创建的是当前页面会话里的临时组件。创建成功后,新组件的 events.create 会立即执行一次:

text
copyComponent("card_template", "card_2")

临时组件不会自动写回页面文件。重新打开页面后,它们会恢复为保存时的结构。

保存校验会扫描当前页面全部生命周期事件、组件事件、自定义方法和计时器回调中的静态 addComponent / copyComponent 声明。因此可以在 open 中创建组件,再在按钮事件或方法中引用同一个动态 ID:

yaml
events:
  open: |-
    addComponent("text", "dynamic_tip")

methods:
  更新提示: |-
    component("dynamic_tip").text.value = "数据已经刷新"

这只解决编辑器保存时的类型识别,不改变运行顺序。如果方法在组件实际创建前执行,对动态组件的那条操作会安全跳过。

reload 的关闭与重开

执行 /chaui reload 时,普通页面、HUD 和每一个世界页面实例都会经历完整生命周期:

  1. 旧页面执行 close
  2. 旧页面的计时器、视频、字体和实体资源被释放;
  3. 服务端载入新页面定义;
  4. 客户端短暂等待 1 tick;
  5. 新页面重新执行 open 和全部初始 create

如果页面已经从配置中删除,只执行旧页面关闭,不再重新打开。关闭确认最多等待 40 tick;未送达的动作不会被服务端自行补造。

GUI 带有子页面时,旧页面先从栈顶一路关闭到根页面;重载完成后再先恢复根页面,然后逐层恢复到原栈顶。每一层都拥有独立变量、输入、计时器和资源作用域,也会分别执行自己的 closeopencreate。如果某一层页面已经缺失、配置无效或不再是 screen,恢复会停在这一层,已经成功恢复的父级仍然保留。容器替换页面作为根页面时,只重建 ChaUI 页面链,不会为了 reload 关闭真实容器。

关闭中间父页面也遵循栈顺序:先从栈顶向下关闭它上方的所有子页面,再关闭目标页面。closeAll() 会一次处理当前 GUI 从栈顶到根页面的整条链,但不会影响 HUD 或世界页面。

客户端与服务端的分工

变量、组件状态、音效、视频控制和生命周期流程在客户端执行。openclosecmdopcmdconsolecmd 等需要服务端参与的动作,只会上报本次实际执行到的动作编号;服务端会从已保存页面和方法中重新确认后执行,不接收客户端上传的命令正文。

编辑器预览

编辑画布本身不执行任何生命周期。点击“预览”后,编辑器会建立页面深拷贝并在本地执行 opencreate、点击、悬浮和 close。预览中的变量、组件修改和临时组件不会污染待保存页面,也不会发送服务端动作或自定义 packet

退出预览会立即停止预览计时器并释放视频、字体和实体资源。