组件对象、布局公式与临时组件
component("组件ID") 会取得当前页面会话中的组件对象。它不是把某一段文字临时替换成数字,也不是直接暴露客户端内部对象;页面只能通过 ChaUI 提供的安全属性读取或修改这个组件。
中文写法完全相同:
组件("组件ID")取得组件对象后,可以继续读取公共属性、父组件、布局对象和当前组件类型自己的配置。例如文本组件可以读取 text.value,按钮可以读取 button.label,图片可以读取 image.path。
在组件事件中使用 self、parent 和 child
组件自己的事件经常需要操作“我自己”或“我所在的面板”。这时不必重复填写组件 ID:
self/自身:触发当前事件的组件;parent/父级:当前组件的父组件,等同于self.parent;component("id")/组件("id"):按 ID 取得当前页面中的指定组件。
三种写法得到的是同一种安全组件对象,因此都能继续读取属性、调用动作或访问子组件。组件对象还可以直接读取当前算出的 x、y、width、height,中文宽高可写成 宽、高。例如 self.width 与 self.layout.width 都会得到当前宽度。
下面是一份可以直接保存的完整页面。点击按钮后,脚本会取得按钮自己、父面板和父面板的第一个子组件,并把结果显示到页面上:
id: component_reference_demo
version: 1
title: "组件引用示例"
size:
width: 240
height: 120
display:
mode: screen
vars:
clickedId: ""
panelId: ""
firstChildId: ""
events: {}
methods: {}
elements:
- id: panel
type: layout_relative
layout:
x: 20
y: 20
width: 200
height: 80
- id: result
type: text
parent: panel
layout:
x: 10
y: 10
width: 180
height: 20
text:
value: "按钮={vars.clickedId},面板={vars.panelId},首项={vars.firstChildId}"
- id: inspect_button
type: button
parent: panel
layout:
x: 10
y: 45
width: 100
height: 20
button:
label: "读取组件"
events:
leftClick: |-
vars.clickedId = self.id
vars.panelId = parent.id
vars.firstChildId = parent.child(0).idchild(index) / 子组件(index) 只读取这一层的直接子组件,索引从 0 开始。上例的 panel.child(0) 是 result,panel.child(1) 是 inspect_button。它不会继续向下搜索孙组件。
子组件顺序是稳定的:页面原有组件按 yml 的 elements 顺序排列;脚本动态新增、复制后放入父级,或把已有组件重新挂到该父级时,会追加到当前子列表末尾。z、坐标和组件 ID 不会改变 child() 的顺序。
可以连续链式访问:
self.parent.child(0).id
component("panel").child(1).button.label
父级.子组件(0).文本.value没有父级、没有对应子组件或索引越界时返回 null。例如 component("panel").child(99) 会得到 null;若继续写 .id,只会让当前语句产生运行时错误,页面其他脚本仍可继续。负数、小数、字符串、布尔值、缺少参数或传入多个参数都会被拒绝。
页面级事件没有触发组件,所以页面的 open、close、键鼠等根级事件中,self 与 parent 都是 null。根组件事件中的 self 正常指向该根组件,但它的 parent 仍是 null。
组件事件调用的自定义方法、sleep 恢复链、timeout、interval、timer、debounce 与 throttle 回调都会保留触发组件上下文,不需要把组件 ID 作为额外参数传入:
methods:
report: |-
log("自身={self.id},父级={parent.id},首项={parent.child(0).id}")
elements:
- id: inspect_button
type: button
parent: panel
events:
leftClick: methods.report()这里的 self、parent 和从 0 开始的 child(0) 与普通组件脚本表达式完全相同,并非 log 的特殊替换规则。
旧布局公式保持原样
布局和其他数值公式中的 self.width/height、parent.x/y/width/height 仍表示公式矩形,不是这里的可空组件对象。根级 parent 继续使用窗口矩形作为回退,因此旧页面不需要修改。child() 属于事件脚本,不能写进数值公式。
一个可以直接照着做的例子
下面这份页面片段包含面板、提示文字和检查按钮。点击按钮后会同时完成三件事:
- 把面板此刻算出的 X 保存到
vars.currentX; - 把面板原始 X 公式保存到
vars.originalFormula; - 让提示文字始终位于面板右侧 1 个 GUI 像素处。
vars:
currentX: 0
originalFormula: ""
elements:
- id: panel
type: rect
pointerEvents: pass
opacity: 0.8
layout:
x: window.width * 0.25
y: 40
width: 120
height: 40
rect:
color: "#203040"
- id: tip
type: text
layout:
x: 0
y: 50
width: 120
height: 20
text:
value: "面板 X:{vars.currentX}\n原公式:{vars.originalFormula}"
textSize: 1
- id: inspect_button
type: button
layout:
x: 20
y: 100
width: 100
height: 20
button:
label: "读取并绑定"
events:
leftClick: |-
vars.currentX = component("panel").layout.x
vars.originalFormula = component("panel").layout.expression("x").source
component("tip").layout.x = formula(
component("panel").layout.x + component("panel").layout.width + 1
)假设点击时窗口宽度是 400:
panel.layout.x的当前计算结果是100,所以vars.currentX得到固定值100;layout.expression("x").source得到原始公式文本window.width * 0.25;tip.layout.x计算为100 + 120 + 1 = 221。
之后把窗口宽度改为 600:
- 面板 X 会重新计算为
150; - 提示文字因为使用了
formula(...),会自动移动到271; vars.currentX仍然是点击时保存的100,除非再次执行读取脚本;vars.originalFormula仍然保存公式文本,不会被计算结果覆盖。
中文等价写法
上面按钮的事件也可以完整写成中文:
events:
leftClick: |-
变量.currentX = 组件("panel").布局.x
变量.originalFormula = 组件("panel").布局.表达式("x").source
组件("tip").布局.x = 公式(
组件("panel").布局.x + 组件("panel").布局.宽 + 1
)中英文可以混用,但同一份页面建议选一种主要风格,方便以后维护。
当前值和原始公式是两回事
每个布局属性都会同时维护声明和当前计算结果:
| 写法 | 得到什么 |
|---|---|
component("panel").layout.x | 当前窗口和变量条件下计算出的数字 |
component("panel").layout.expression("x").source | 保存时使用的原始公式文本 |
component("panel").layout.expression("x").isFormula | 该属性是否保存为响应式公式 |
expression 只接受 x、y、width、height。中文也可以写 表达式("宽") 或 表达式("高")。
如果布局原本是固定数字 20,读取 layout.x 会得到 20,而 isFormula 为 false。如果布局原本是 window.width * 0.5,layout.x 会得到当前计算结果,source 会保留公式文本,isFormula 为 true。
普通等号是快照,formula 才会持续跟随
下面两段看起来相似,结果并不相同。
一次性快照:
events:
leftClick: |-
component("tip").layout.x = component("panel").layout.x + component("panel").layout.width + 1执行这一刻先算出数字,再把数字保存到 tip.layout.x。窗口改变后,tip 不会继续跟随。
响应式公式:
events:
leftClick: |-
component("tip").layout.x = formula(
component("panel").layout.x + component("panel").layout.width + 1
)这里保存的是表达式。面板位置、面板宽度、页面变量或窗口尺寸改变后,ChaUI 会按依赖顺序重新计算,不依赖组件在 yml 中的先后顺序。
用字符串保存公式
公式也可以写成带引号的字符串。字符串仍会交给同一个公式解析器检查,不会作为任意脚本执行。
events:
leftClick: |-
component("panel").layout.x = formula("window.width * 0.5")这种写法适合公式来自配置文本的场景。字符串内容必须是一条完整的数字公式;formula("1); cmd('执行某项业务')") 会被拒绝,因为它不是合法公式。
读取父组件
component("id").parent 返回该组件在当前页面会话中的父组件对象。因此不需要自己再写一次父布局 ID:
events:
create: |-
vars.parentX = component("child_title").parent.layout.x
vars.parentWidth = component("child_title").parent.layout.width根级组件没有父组件,读取它的 parent 会得到 null。不要继续对根组件写 .parent.layout.x;该条语句会被安全跳过。
设置组件父级
parent 也可以在脚本中修改。最直观的写法是把一个布局组件对象直接赋给它:
events:
leftClick: |-
component("d3").parent = component("panel")这表示把 d3 放进布局组件 panel。父级必须是 layout_absolute、layout_relative、layout_grid 或 layout_scroll,普通文本、按钮等组件不能作为父级。
如果希望 d3 和 test3 进入同一个父布局,可以直接复制 test3 的父组件对象:
events:
leftClick: |-
component("d3").parent = component("test3").parent下面几种写法也都有效:
component("d3").parent = component("test3").parent.id
component("d3").parent = "panel"
component("d3").parent = null
组件("d3").父级 = 组件("test3").父级.parent.id得到父级 ID 字符串;- 直接写
"panel"也是按父级 ID 设置; null表示取消父级,让组件回到页面根级;- 不存在的父级、非布局父级和循环嵌套会被拒绝。
换父级不会偷偷改写 d3 的 layout.x/y。如果新父级是相对布局,原来的 X、Y 会被当作新父级内的局部坐标,所以组件在屏幕上的位置可能发生变化。
可以读取哪些属性
组件对象可以安全读取:
- 公共字段:
id、type、visible、enabled、z、pointerEvents、scale、rotation、opacity、条件、提示和事件信息; - 父级:
parent; - 布局:
layout.x/y/width/height和layout.expression(...); - 对应组件类型的数据块,例如
text.value、button.label、image.path、input.value、video.volume、entity.displayName;物品槽还可以读取itemSlot.check。
读取结果可以用于变量赋值、条件、普通运算和 formula(...)。log 的花括号只直接读取 vars 与 vals,所以调试组件属性时先保存到变量:
events:
leftClick: |-
vars.currentPath = component("logo").image.path
vars.currentWidth = component("logo").layout.width
log("图片:{vars.currentPath},宽度:{vars.currentWidth}")读取范围比写入范围更广。写入仍只允许 ChaUI 明确开放的临时状态,例如显隐、启用、父级、四项布局、部分文字/图片/视频/输入框/实体属性;id、type、公式元数据和 itemSlot.check 仍是只读的。
itemSlot.check 是页面 yml 或编辑器“操作条件”保存的客户端发包前置条件。脚本可以读取它用于提示或调试,但不能在运行时改写:
events:
leftClick: |-
vars.slotRule = component("submit_slot").itemSlot.check
log("当前操作条件:{vars.slotRule}")条件没通过时只会阻止内置槽位操作包,当前 leftClick 脚本仍然执行。因此上面的日志在槽位被禁止操作时也能显示。
指针处理、缩放与透明度
组件对象可以读取这三个根级字段,也可以在当前页面会话中修改:
events:
leftPress: |-
component("confirm_button").scale = 0.96
leftRelease: |-
component("confirm_button").scale = 1
leftClick: |-
component("dialog_mask").pointerEvents = "pass"
component("dialog_mask").opacity = 0直接赋数字是一次性值。需要持续跟随变量时使用 formula(...):
events:
create: |-
component("dialog").scale = formula("vars.zoom")
component("dialog").rotation = formula("vars.angle")
component("dialog").opacity = formula("vars.fade / 100")以后修改 vars.zoom、vars.angle 或 vars.fade,组件会重新计算。component("dialog").scale、.rotation 与 .opacity 读取的是当前算出的数字。运行期间变量暂时让公式无效时,组件会保留上一次合法结果;首次失效时 scale 与 opacity 使用 1,rotation 使用 0。中文属性名可写为 组件("dialog").旋转。
布局组件不能设置 scale、rotation 或 opacity。实体支持根级 scale 与 rotation,但不支持根级 opacity。opacity 不会关闭命中;需要让组件不再遮挡时,应同时设置 pointerEvents = "pass" 或隐藏组件。
销毁当前组件
组件自己的事件可以调用 self.destroy() / 自身.销毁(),立即从当前页面会话中销毁触发事件的组件。早期资料中误拼写的 self.destory() 继续兼容,新脚本建议统一使用 destroy。
- id: one_time_tip
type: button
layout:
x: 20
y: 20
width: 100
height: 20
button:
label: "点击后移除"
events:
leftClick: |-
self.destroy()点击后,one_time_tip 会从这次页面会话中移除,并释放它的提示、拖拽、滚动、视频、实体和视觉状态。它的直接子组件不会一起销毁,而是解除父级后继续保留;需要移除整组组件时,应让各组件分别处理销毁,或在页面设计中控制整组显隐。
页面级事件没有 self,不能调用此方法。组件销毁后,同一条后续脚本或延时回调再次访问旧引用时,只会让当前失败语句停止,不会影响页面其他脚本。
保存或重置拖动位置
启用了 dragMode 的组件可以让玩家调整位置。脚本还能把当前实际偏移保存到客户端本地,或删除记忆并立即回到页面原始布局位置:
component("movable_panel").savePosition()
component("movable_panel").resetPosition()savePosition() 适合“临时拖动,点击确认后再记住”的设计。即使组件使用 dragMode: temporary,也能在确认按钮脚本中主动保存当前位置:
- id: movable_panel
type: layout_relative
dragMode: temporary
layout:
x: 40
y: 30
width: 180
height: 100
- id: save_layout
type: button
layout:
x: 40
y: 140
width: 80
height: 20
button:
label: "保存位置"
events:
leftClick: component("movable_panel").savePosition()
- id: reset_layout
type: button
layout:
x: 130
y: 140
width: 80
height: 20
button:
label: "恢复默认"
events:
leftClick: component("movable_panel").resetPosition()resetPosition() 会删除这个组件在当前服务器、当前玩家和当前页面下的记忆,取消它正在进行的拖动,并让当前页面实例立刻回到原始布局结果。已有记忆与当前 dragMode 无关:把模式改为 off 只会禁止继续拖动,不会自动删除记忆。
中文写法为:
组件("movable_panel").保存位置()
组件("movable_panel").重置位置()脚本动作只处理指定组件。管理员要一次重置某位在线玩家的全部组件位置记忆时,请使用对应的服务端指令或 ChaUIAPI.resetRememberedComponentPositions。
常用写入
events:
leftClick: |-
component("detail_panel").visible = true
component("confirm_button").enabled = false
component("confirm_button").pointerEvents = "block"
component("confirm_button").scale = formula("vars.buttonScale")
component("confirm_button").opacity = 0.85
component("title").text.value = "新的标题"
component("confirm_button").button.path = "gui/button_active.png"
component("preview").image.path = "gui/result.gif"
component("name_input").input.value = "默认名称"修改图片、按钮图片或 GIF 路径后,新素材会从第一帧重新开始显示。
读取和修改源图选区
图片、按钮、输入框、物品槽和物品展示的源图选区也属于组件对象。读取字段本身会得到当前渲染条件下算出的整数:
vars.currentSourceWidth = component("health_fill").image.sourceWidth读取保存的声明要在对应数据块上调用 expression("字段名"):
vars.currentSourceFormula = component("health_fill").image.expression("sourceWidth").source
vars.sourceIsFormula = component("health_fill").image.expression("sourceWidth").isFormula如果字段原本是固定数字,source 返回这个数字的文本形式,isFormula 为 false。如果字段保存的是响应式公式,source 保留公式原文,isFormula 为 true。
下面是一段完整的按钮事件。它先让血条源宽持续跟随玩家血量,再记录当前值和原公式,最后把结果显示在本地聊天栏:
events:
leftClick: |-
component("health_fill").image.sourceWidth = formula(
clamp(vals.player.health / vals.player.maxHealth, 0, 1) * 100
)
vars.currentSourceWidth = component("health_fill").image.sourceWidth
vars.currentSourceFormula = component("health_fill").image.expression("sourceWidth").source
log("当前源宽:{vars.currentSourceWidth}")
log("源宽公式:{vars.currentSourceFormula}")直接赋数字会清除旧公式,变成一次性固定值:
component("health_fill").image.sourceWidth = 50各组件可以使用的字段如下:
| 数据块 | 可读写的源图字段 |
|---|---|
image | sourceX/Y/Width/Height |
button | source*、hoverSource*、checkedSource* |
input | source*、focusSource* |
itemSlot | sourceX/Y/Width/Height |
itemDisplay | sourceX/Y/Width/Height |
所有源图公式都使用当前页面的 vars、vals、窗口、父级和自身上下文重新计算,小数向下取整。脚本修改只属于当前页面会话,不会保存到服务端 yml。完整的图集与无拉伸血条示例见图片裁剪与动态血条。
实体组件可以写入已开放的 entity.* 状态,例如:
events:
leftClick: |-
component("npc_preview").entity.displayName = "任务向导"
component("npc_preview").entity.showName = true
component("npc_preview").entity.yaw = 180
component("npc_preview").entity.orthographic = true
component("npc_preview").entity.trackMouse = trueentity.orthographic 只能写入布尔值。上面的脚本会立即切换为正交投影;写回 false 会恢复默认的 30 度透视投影。也可以用 vars.mode = component("npc_preview").entity.orthographic 读取当前模式。脚本改动只作用于当前页面会话,不会改写服务端页面文件。
动态修改原版容器绑定
容器替换页面中的非布局组件可以读取或修改 containerBinding。下面脚本先读取菜单按钮当前绑定,再让详情物品跟随同一槽位:
vars.currentBinding = component("menu_button").containerBinding
component("detail_item").containerBinding = component("menu_button").containerBinding从页面变量设置固定语义槽位也可以:
vars.targetBinding = "container_13"
component("detail_item").containerBinding = vars.targetBinding解除绑定必须使用 null:
component("detail_item").containerBinding = null修改只属于当前打开的容器会话,不写回页面配置。非法或超出当前容器范围的绑定会跳过当前赋值并保留旧值。完整槽位编号、组件点击和 Lore 用法见槽位、按钮与物品信息。
动态修改物品槽绑定与模式
普通虚拟 item_slot 可以在当前页面会话中修改 itemSlot.bind 和 itemSlot.mode。切换到持久槽时,先写入已注册的 bind,再写 mode:
component("动态槽").itemSlot.bind = "宝石槽_1"
component("动态槽").itemSlot.mode = "persistent"中文写法等价:
组件("动态槽").物品槽.绑定 = "宝石槽_1"
组件("动态槽").物品槽.模式 = "persistent"顺序很重要。若先切换为 persistent,ChaUI 会用旧 bind 检查注册表;旧值未注册时,本次赋值会被拒绝并保留原状态。目标 ID 没有注册、模式与绑定不匹配或组件不是物品槽时,也只拒绝当前赋值。
修改不会写回页面 yml。客户端会先用当前服务器同步的注册表预检,实际槽位操作仍由服务端重新验证并裁决。中文 ID、acceptWhen 和 reload 规则见槽位注册表。
公式依赖和循环
ChaUI 会根据“组件 ID + 布局字段”建立依赖关系。例如 B 的 X 引用 A 的 X,C 的 X 又引用 B 的 X,ChaUI 会先计算 A,再计算 B,最后计算 C。
如果新公式形成循环,例如 A 依赖 B,同时 B 又依赖 A,本次公式绑定会被拒绝,组件会保留之前仍然有效的声明和值,不会把整个页面算崩。
新增和复制临时组件
addComponent 会在当前页面会话中新增默认组件,copyComponent 会复制已有组件:
events:
leftClick: |-
addComponent("text", "temporary_tip")
component("temporary_tip").text.value = "这是临时生成的提示"
component("temporary_tip").layout.x = 20
component("temporary_tip").layout.y = 80
copyComponent("temporary_tip", "temporary_tip_2")
component("temporary_tip_2").layout.x = 140中文函数为 新增组件 和 复制组件。addComponent 的类型只接受当前支持的 17 种组件:image、video、text、button、rect、input、dropdown、toggle、slider、progress、item_slot、item_display、entity、layout_absolute、layout_relative、layout_grid、layout_scroll。自定义类型或拼错的类型不能创建。
两个动作的新 ID 都只能包含 Unicode 字母、Unicode 数字、_ 和 -,并且不能和当前页面已有 ID 重复。例如 任务提示_2、card-3 可以使用,含空格、点号或斜杠的 ID 不可以。新增或复制成功后,新对象会立即执行自己的 events.create。
copyComponent(source, target) 只复制来源组件本身,不会把源组件的子组件一起复制。源组件处于某个布局容器中时,复制体会保留相同父级;源组件本来就在根级时,复制体也在根级。同一段脚本可以紧接着使用新 ID:
copyComponent("temporary_tip", "temporary_tip_2")
component("temporary_tip_2").layout.x = 120
// parent 是组件对象;加上 .id 才得到纯文本 ID
vars.parentId = component("temporary_tip_2").parent.id
log("复制体父级={vars.parentId}")保存页面时,copyComponent 的源组件可以暂时不存在,便于先写好跨事件或计时器脚本;这不会自动创建源组件。真正执行复制语句时,源组件必须已经存在,否则只终止当前复制语句,后续语句仍会继续执行。
连同全部子组件一起复制
需要复制一整张卡片、列表项或组合面板时,使用 copyComponentTree(source, suffix);中文写法是 复制组件树(source, suffix)。第一个参数是来源根组件的固定 ID,第二个参数是追加到每个来源 ID 后面的字符串,也可以使用字符串表达式。
假设原结构为:
| 来源 ID | 父级 | 用途 |
|---|---|---|
card | 根级 | 卡片布局 |
card_icon | card | 卡片图标 |
card_title | card | 卡片标题 |
执行:
copyComponentTree("card", "_副本")
component("card_副本").layout.x = 180会一次生成 card_副本、card_icon_副本 和 card_title_副本。两个子组件的父级会分别改为 card_副本,自身的局部 X、Y 不变,因此整张卡片会保持原来的内部排布。编辑器里的“复制”按钮同样会复制完整子树,但会为副本自动分配新 ID,并只给副本根节点增加位置偏移。
后缀不能为空。最终生成的每个 ID 只能包含 Unicode 字母、数字、_ 和 -,并且最多为 64 个 Unicode 字符。执行前会先检查整棵子树:只要任意新 ID 已存在、格式非法或过长,整次复制失败,不会留下只复制了一半的组件。
脚本正文不会重写
复制会重建组件定义和副本内部的父级关系,但不会自动改写事件或自定义方法正文中手写的组件 ID。上例若 card_title 的点击脚本写了 component("card"),复制后仍然指向原来的 card;需要按业务需求改为通过 self、parent 访问,或主动设置副本状态。
copyComponent 与 copyComponentTree 的区别很明确:前者的第二个参数是完整目标 ID,并且只复制一个组件;后者的第二个参数是统一后缀,并递归复制来源根组件和全部后代。
如果把父级对象本身存入变量,log("{vars.parentObject}") 会显示类似 component("panel") 的调试文字:
vars.parentObject = component("temporary_tip_2").parent
log("{vars.parentObject}")这些组件只存在于当前客户端页面会话,不会发起编辑器保存,也不会修改服务端页面文件。重新打开页面后,临时组件会消失。
跨事件引用动态组件
动态组件可以在一个事件中创建,在另一个事件、方法或计时器中使用。下面的页面打开时创建 d3,按钮点击时再修改它:
events:
open: |-
addComponent("text", "d3")
elements:
- id: update_button
type: button
layout:
x: 20
y: 20
width: 100
height: 20
button:
label: "更新动态文字"
events:
leftClick: |-
component("d3").text.value = "按钮已经点击"编辑器保存时会检查整张页面的事件、方法和计时器脚本,因此不会再把这里的 d3 当成未知组件。但是运行顺序仍然重要:如果某条引用语句实际执行时 d3 还没创建,ChaUI 只会跳过那一条语句,不能提前生成组件。
动态组件 ID
普通脚本允许用字符串表达式计算组件 ID,适合配合 repeat 的索引变量批量处理同一组组件:
repeat(4, vars.i) {
component("entry_" + vars.i).enabled = vars.i != vars.disabledIndex
component("entry_text_" + vars.i).text.value = "条目 " + (vars.i + 1)
}保存时仍会检查参数是否可能返回字符串,并继续检查字段名是否属于 ChaUI Script 的公开组件属性。执行时,计算结果必须是当前页面中真实存在的完整组件 ID,目标组件也必须支持所访问的类型数据块;否则只终止当前失败语句。
动态组件 ID 不能写进 formula(...)。响应式公式必须使用固定组件 ID,以便保存时建立确定的组件依赖图:
// 支持:普通脚本在执行时写入固定值
component("entry_" + vars.i).layout.x = vars.i * 24
// 支持:formula 使用固定组件依赖
component("tip").layout.x = formula(component("panel").layout.x + 8)
// 不支持:formula 内动态选择依赖组件
component("tip").layout.x = formula(component("entry_" + vars.i).layout.x)先写尚未创建的组件动作
有时你会先完成按钮逻辑,之后才在编辑器里补上目标组件;也可能由另一段脚本在运行期间创建目标组件。这种情况下,可以直接保存尚不存在的组件引用:
component("future_tip").visible = true
component("future_tip").text.value = "操作完成"
vars.actionFinished = true编辑器不会只因为 future_tip 当前不在组件列表中而拒绝整张页面。语法、字段名、动作参数和已经存在组件的类型仍会正常检查;例如已经存在的文本组件不能调用视频动作,拼错的字段也不能保存。
真正执行到引用语句时,目标组件必须已经存在,并且类型要和所用的数据块或动作相符。若目标仍不存在或类型不符,只终止当前这一条语句,后面的 vars.actionFinished = true 仍会继续执行。客户端不会在聊天栏刷提示;同一页面会话中的同类错误只会在 latest.log 记录一次 warning,便于管理员排查组件 ID 和执行顺序。
下面的写法先创建组件,再使用预先写好的动作:
addComponent("text", "future_tip")
component("future_tip").text.value = "现在已经可以使用"
component("future_tip").visible = true重新打开页面或执行 reload 后会建立新的页面会话;如果同类错误仍然存在,新会话会再次记录一次,避免旧日志状态掩盖当前配置问题。
常见错误
| 错误 | 结果与处理方式 |
|---|---|
| 组件 ID 写错或组件不存在 | 页面仍可保存,但执行时当前语句会停止并在 latest.log 留下一条去重 warning;先检查组件 ID 和创建顺序。 |
根组件继续读取 .parent.layout.x | 根组件的 parent 是 null。只对确实设置了父布局的子组件读取。 |
使用 layout.right | ChaUI 没有这个字段。右边位置请写 layout.x + layout.width。 |
formula("window.width *") | 公式不完整,保存或绑定会被拒绝。 |
| A 和 B 的公式互相引用 | 形成循环,本次新绑定被拒绝,旧的有效公式和值继续保留。 |
给 component("a").id 赋值 | id 是只读字段。需要新 ID 时使用复制或在编辑器中创建组件。 |
给 component("slot").itemSlot.check 赋值 | itemSlot.check 是只读配置。请在页面 yml 或编辑器“操作条件”中修改。 |
把普通组件赋给 .parent | 父级必须是布局组件。请改为目标布局组件对象、它的 ID,或使用 null 回到根级。 |
继续阅读变量与条件,了解组件对象如何与页面变量配合;需要页面跳转和服务端动作时阅读内置动作、日志与音效。
猹件开发组