2018 年查看项目共通处理时,我发现:表单改动过,用户再执行某个按钮操作,才出现确认提示。本以为需要逐个给输入框绑监听,实际关键只有几行——在 form 上监听 change,再加一个类名标记。

子控件的 change 可以到达表单

在 DOM 就绪且已有 jQuery 的页面中:

$(function () {
    $("#profileForm").on("change.dirtyMarker", function () {
        $(this).addClass("form-changed");
    });
});

事件从相关控件传到表单,因此无需为每个已存在的输入框复制相同逻辑。使用 on 的写法要求 jQuery 1.7 及以上;.dirtyMarker 是事件命名空间,便于只管理这一组监听。jQuery on

这记录的是收到 change 事件,不是对全部字段做实时比较。文本输入的 change 与每个按键的 input 事件也不等价。

怎样使用这个标记

例如,对一个明确为 type=button 的后续操作,可以先判断是否需要确认:

$("#continueButton").on("click.dirtyMarker", function () {
    var changed = $("#profileForm").hasClass("form-changed");
    if (changed && !window.confirm("表单发生过变更,仍要继续吗?")) {
        return;
    }
    console.log("允许进入后续操作");
});

这是使用标记的交互示例,未包含保存接口或离开页面的全套逻辑。真正的业务动作应放在用户确认之后,不能先发请求再询问。

改回原值,标记仍然可能存在

这个标记只增不减。用户输入后又改回初值,仍可能带着 form-changed;因此它适合表达“发生过变更事件”,不是严格的“当前存在未保存内容”。

如果需要精确脏数据判断,应在加载完成时保存一个规范化基线,与当前业务字段比较。多选顺序、空白、数字格式、禁用控件、文件和富文本都需明确规则;不能只用一次表单序列化就假设覆盖所有状态。

保存、重置和程序赋值各有边界

  • 只有保存被服务端确认成功后,才能更新基线并清除相应标记。
  • 若保存期间用户继续编辑,不能无条件清掉这些较新的改动。
  • 表单 reset 或重新加载数据后,应在实际值恢复完成时同步标记/基线,而不是仅观察重置按钮被点击。
  • 程序调用 val 设置值通常不会自动触发 change;需要事件通知时要显式安排,并防止重复业务副作用。jQuery val

先明确需求是“曾改动”还是“当前偏离初始内容”,再选择事件标记或状态比较。两者不是同一个算法。