FORGE KUI / learn

表单取值、校验与保存

读取当前输入,保存成功后更新状态;无效输入保持原有数据。

版本 3.61.7

第03课
准备
能运行设置页并找到 main.cpp
学完可以做
实现当前值读取、校验、保存和恢复
下载工程 ↓settings-lab.zip

当前值与初始属性

HTMLInputElement::value() 返回用户当前编辑的内容;value 属性表示默认值,两者可能不同。复选框用 isChecked() 读取当前状态。设置工程使用动态类型检查,文档结构改变导致节点缺失时立即退出。

cpp
    auto* name = dynamic_cast<kui::HTMLInputElement*>(doc->getElementById("display-name"));
    auto* notifications = dynamic_cast<kui::HTMLInputElement*>(doc->getElementById("notifications"));
    auto* save = doc->getElementById("save");
    auto* reset = doc->getElementById("reset");
    auto* status = doc->getElementById("status");
    auto* revision = doc->getElementById("revision");
    if (!name || !notifications || !save || !reset || !status || !revision) return 2;

业务数据模型

SettingsState 保存名称、通知选项和成功次数。校验拒绝仅含空格、Tab、换行或超过 256 个 UTF-8 字节的名称;失败时不修改已有数据。页面 maxlength=64 限制编辑长度,宿主仍独立检查数据。

cpp
#pragma once
#include <string>
#include <utility>

// 练习项目只保存在内存中,退出后恢复默认值。
struct SettingsState {
    std::string name = "Studio";
    bool notifications = true;
    unsigned revision = 0;

    bool save(std::string nextName, bool nextNotifications) {
        const auto begin = nextName.find_first_not_of(" \t\r\n");
        if (begin == std::string::npos) return false;
        const auto end = nextName.find_last_not_of(" \t\r\n");
        nextName = nextName.substr(begin, end - begin + 1);
        if (nextName.size() > 256) return false;
        name = std::move(nextName);
        notifications = nextNotifications;
        ++revision;
        return true;
    }
};

保存回调

点击保存时读取控件当前值。校验失败显示错误;成功后更新状态和计数。用户输入通过 setTextContent 作为文本显示,不把输入拼接成 HTML。此回调在 UI 线程执行,不适合直接放入耗时网络操作。

cpp
    save->addEventListener("click", [&](kui::Event&) {
        // value() 是当前输入;value 属性是初始值,两者不能混用。
        if (!state.save(name->value(), notifications->isChecked())) {
            name->setAttribute("aria-invalid", "true");
            status->setAttribute("data-state", "error");
            status->setTextContent(english ? "Enter a display name (up to 256 UTF-8 bytes)."
                                         : "请输入显示名称(最多 256 个 UTF-8 字节)。");
            return;
        }
        name->removeAttribute("aria-invalid");
        status->setAttribute("data-state", "success");
        status->setTextContent((english ? "Saved in this session: " : "本次会话已保存:") + state.name);
        revision->setTextContent(std::to_string(state.revision));
    });

恢复未保存的编辑

恢复按钮使用上次成功保存的数据更新控件。setValue 和 setChecked 用于设置当前状态;恢复不增加保存次数。修改名称但不保存,再点击恢复即可观察。

cpp
    reset->addEventListener("click", [&](kui::Event&) {
        name->setValue(state.name);
        notifications->setChecked(state.notifications);
        name->removeAttribute("aria-invalid");
        status->setAttribute("data-state", "idle");
        status->setTextContent(english ? "Restored the last saved values." : "已恢复上次保存的内容。");
    });

交互检查

用以下操作检查实际窗口。数据模型的自动回归可通过 CTest 运行;它不替代窗口内的输入和键盘检查。

  • 将名称改为 Workbench 并保存:状态显示新名称,次数增加。
  • 将名称改为空格并保存:显示错误,次数不变。
  • 输入 <h1>Test</h1> 并保存:状态显示原样文字。
  • 修改未保存内容后恢复:名称与复选框回到上次保存值。

当前 SDK 的键盘限制

Windows x64 SDK 3.61.7 的课程实测中,Tab 可以聚焦按钮,但 DevTools 注入的 Enter 未触发保存 click。鼠标点击保存可工作;该结果不证明所有原生键盘路径,也不能宣称全键盘验收通过。

动手练习与验收

用这些动作确认自己完成了本课,不必额外抄一份同样的代码。

  • 有效名称保存后计数增加,空白名称被拒绝且计数不变。
  • 输入 <h1>Test</h1>,结果仍是普通文字。
  • 输入未保存名称后恢复,回到上次成功保存值。
  • 退出并重开:本课程只保存进程内数据,不是磁盘持久化。

文档有误或遗漏?

反馈此页问题 →