跳到主要内容

表单模块与生命周期

每个通过 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。

下一步:事件与命令。