表单模块与生命周期
每个通过 RegisterForm(name, module) 注册的表单模块都是一个 Lua table。本页说明它的
三个成员函数,以及主表单与子表单的区别。
模块接口
local myForm = {}
function myForm.uiSchema(form) end -- 返回 schema(必需)
function myForm.validateForm(form) end -- 返回 nil 或错误字符串(可选)
function myForm.submitForm(form, userArgs) end -- 返回 nil 或错误字符串(可选)
return myForm
uiSchema(form)
返回界面的 schema。form 是当前表单值,用于动态生成界面。详见 表单 schema 组件。
validateForm(form)
校验表单:
- 返回
nil或空字符串:校验通过; - 返回非空字符串:校验失败,字符串会作为错误信息展示,并阻止提交。
function myForm.validateForm(form)
if #(form.selectedItems or {}) == 0 then
return "请至少选择一项"
end
return nil
end
submitForm(form, userArgs)
提交时执行,userArgs 是打开表单时透传的参数(见子表单)。同样返回 nil 表示成功,
返回字符串表示失败。
function myForm.submitForm(form, userArgs)
PushCommand("items", "addItems", form.selectedItems)
return nil
end
字段级校验
除了模块级的 validateForm,还可以给单个字段加 validate 函数:
{
type = "number",
field = "count",
label = "数量",
validate = function(form)
if (form.count or 0) <= 0 then
return "数量必须大于 0"
end
return nil
end,
}
框架会遍历 schema 中所有带 field 且有 validate 的项,依次调用;任意一个返回非空字符串
即校验失败,错误信息形如 字段<count>校验失败:数量必须大于 0。
主表单 vs 子表单
通过 RegisterForm 的 name 区分:
-
主表单:名为
"main",显示在任务面板中。- 提交时(面板「提交」按钮)会先调用主表单的
validateForm,然后把表单值保存为该任务的配置, 任务启动时可通过全局变量CurrentSettings读取。 - 主表单的
submitForm不会在「提交」时调用。 - 若没有调用
getUISettings传formName,默认返回主表单。
- 提交时(面板「提交」按钮)会先调用主表单的
-
子表单:其它任意名字(如
"selectUseItem"),通过PushCommand(nil, "openForm", ...)以弹窗方式打开。- 打开时会用
getUISettings取子表单的默认值(子表单不读取已保存配置),再渲染 schema。 - 用户点「确认」时,依次调用该子表单的
validateForm与submitForm。 - 子表单的字段值不会自动保存,通常用于「选择后把结果推送给父表单」。
- 打开时会用
子表单完整流程
以「背包设置」为例:
ui/main.lua(主表单按钮打开子表单)
{ type = "button", label = "添加使用物品", event = "addUseItem",
click = function(form)
PushCommand(nil, "openForm", {
formName = "selectUseItem",
title = "添加使用物品",
-- userArgs 会透传给子表单的 submitForm
userArgs = {},
})
end,
}
ui/form_select_use_item.lua(子表单)
local selectUseItem = {}
function selectUseItem.uiSchema()
return {
type = "table",
children = {
{ type = "checkboxSelectList", field = "selectedItems", options = buildOptions() },
},
}
end
function selectUseItem.validateForm(form)
if #form.selectedItems == 0 then return "请选择物品" end
return nil
end
function selectUseItem.submitForm(form, userArgs)
-- 把选中的物品作为命令推送给父表单的列表
local items = {}
for _, name in ipairs(form.selectedItems) do
table.insert(items, { label = name })
end
PushCommand("useItems", "addItems", items)
return nil
end
return selectUseItem
兼容:全局函数写法
除 RegisterForm 之外,框架也兼容以全局函数命名的方式(不推荐新代码使用):
uiSchema_<name>(form)/validateForm_<name>(form)/submitForm_<name>(form, userArgs)- 没有前缀的
uiSchema/validateForm/submitForm视为主表单。
RegisterForm 的模块优先。若都找不到,打开表单时会报 uiSchema for 'xxx' not found。
下一步:事件与命令。