了解 html 表单是否已更改

Find out if html form has changed

本文关键字:是否 html 表单 了解      更新时间:2023-09-26

使用jquery,我在表单中添加了一个更改处理程序。这在更改任何输入时有效,但仅当用户手动更改输入时,而不是在其他代码更改输入时。

有没有办法检测表单是否已更改,即使其输入被代码更改?

是的,似乎对此有些困惑。在理想情况下,您会期望每当输入发生变化时就会发生onchange事件,但事实并非如此。我敢肯定有充分的理由 - 也许不是。

我克服这个障碍的一种方法是在显示表单状态后将其捕获到变量中,然后在提交之前检查状态是否已更改并采取相应措施。

序列化函数返回的易于存储的状态。存储状态的一个简单位置是使用数据功能。序列化和数据都可以通过jquery获得。

当然,您可以使用其他不同形式的状态(某种形式的哈希)或存储(例如标准全局变量)。

下面是一些原型代码:

如果您的表单 ID 是"xform",那么您可以在表单显示时调用以下代码:

$('#xform').data('serialize',$('#xform').serialize());

然后,当您需要检查时,例如在按钮提交之前,您可以使用:

if($('#xform').serialize()!=$('#xform').data('serialize')){
    // Form has changed!!!
}

您可以将所有这些打包到复制和粘贴javascript片段中,该片段将为您提供一个formHasChanged()函数,可以在您需要的任何地方调用(未测试):

$(function() {
    $('#xform').data('serialize',$('#xform').serialize());
});
function formHasChanged(){
    if($('#xform').serialize()!=$('#xform').data('serialize')){
        return(true);
    }
    return(false);
}

但是我会在这里停止,否则我将创建另一个jquery插件。

序列化表单当然是一种选择,但在以下情况下将不起作用:

  • 您想知道哪些字段已更改
  • 它只需要检查字段的子集
  • 动态添加或删除字段。

幸运的是,每个表单元素都有一个与其对象关联的默认值:

  • 输入,文本区域:默认值
  • 复选框,单选按钮:默认选中
  • 选择
  • :默认已选择

例如:如果输入或文本区域已更改,则 ckeck:

var changed = false;
$(":text,textarea").each(function(){
    changed = this.value != this.defaultValue;
    return !changed; // return if at least one control has changed value
});

很容易在没有jQuery的JavaScript中实现。 initChangeDetection()可以多次调用:

function initChangeDetection(form) {
  Array.from(form).forEach(el => el.dataset.origValue = el.value);
}
function formHasChanges(form) {
  return Array.from(form).some(el => 'origValue' in el.dataset && el.dataset.origValue !== el.value);
}

在 JS 箱上测试


对于不支持较新箭头/数组函数的旧版浏览器:
function initChangeDetection(form) {
  for (var i=0; i<form.length; i++) {
    var el = form[i];
    el.dataset.origValue = el.value;
  }
}
function formHasChanges(form) {
  for (var i=0; i<form.length; i++) {
    var el = form[i];
    if ('origValue' in el.dataset && el.dataset.origValue !== el.value) {
      return true;
    }
  }
  return false;
}

不是常规方式。

可以使用输入进行更改,然后触发更改事件。

$('#inputId').val('foo').trigger('change');

或者有了这个:

$('#inputId').val('foo').change();

这是我所做的(我使用 zif 的答案找到了我的解决方案)

$("form").change(function() {
    $(this).data("changed","true");
});
$("input[type='submit']").click(function() {
    if($("form").data("changed") == "true") {
        var discard = confirm("Some unsaved changes. Discard them ?");
        if(!discard) return false;
    }
});

使用vanilla javascript,您可以对输入的值进行哈希处理

您可以对表单的值进行哈希处理。我建议只使用每个输入的名称作为键,将值用作值。然后,您可以使用查询选择器遍历表单的每个输入以获取哈希。

要检查表单中的值是否更改,您可以比较表单的哈希值。我将初始哈希存储在表单的数据属性中。

下面是一个可能的实现:

function initFormHash(form) {
    form.setAttribute("data-initial-hash", getFormHash(form));
}
function getFormHash(form) {
    const formValues = {};
    form.querySelectorAll("input").forEach(input => {
        const inputType = input.getAttribute("type");
        const inputName = input.getAttribute("name");
        if (inputType === "hidden") return;
        if (!inputName) return;
        if (inputType === "checkbox" || inputType == "radio") {
            formValues[inputName] = input.checked;
            return;
        }
        formValues[inputName] = input.value;
    });
    form.querySelectorAll("textarea, select").forEach(textarea => {
        const name = textarea.getAttribute("name");
        if (!name) return;
        formValues[name] = textarea.value;
    })
    return JSON.stringify(formValues);
}
function formChanged(form) {
    return (form.getAttribute("data-initial-hash") !== getFormHash(form));
}

尝试onchange属性根据 W3c,只要元素的内容、选择或选中状态发生更改,它就会触发。