为什么自定义验证消息导致我的 HTML 表单元素保持无效?

Why are custom validation messages causing my HTML form elements to stay invalid?

我在 pattern 验证规则的输入中实现了自定义验证消息,同时保留 required 的默认消息。但是,当我这样做时,一旦输入无效,它就永远不会再次有效,即使我满足 pattern 标准。

document.addEventListener("DOMContentLoaded", function () {
  const txtUsername = document.getElementById("UserName");
  txtUsername.oninvalid = function (e)
  {
    const input = e.target;
    if (input.validity.patternMismatch)
    {
      input.setCustomValidity("Usernames cannot contain the @ symbol");
    }
  }
})
<form onsubmit="event.preventDefault(); alert('Form submitted');" action="post">
  <!--pattern regex prohibits use of the @ symbol-->
  <input id="UserName" type="text" pattern="^((?!@).)*$" required />
  <button type="submit">Submit</button>
</form>

JSFiddle demo

当我删除我的自定义 oninvalid 事件处理程序时,不会出现此问题。我做错了什么?

还有一个问题,虽然对我解决这个问题不是必不可少的:为什么 Chrome 的内置验证弹出文本动画如此缓慢和断断续续,几乎就像存在某种性能瓶颈一样?我的机器功能强大,对任何其他类型的图形处理都没有问题。

首先,根据 MDN:

It's vital to set the message to an empty string if there are no errors. As long as the error message is not empty, the form will not pass validation and will not be submitted.

这与the HTML standard says一致:

Suffering from a custom error

When a control's custom validity error message (as set by the element's setCustomValidity() method or ElementInternals's setValidity() method) is not the empty string.

一个元素 满足其约束条件 如果它不存在任何上述有效性状态。

如果确定表单域有效,您的示例不会清除自定义错误。因此,一旦该字段被确定为无效,它将在会话的剩余部分保持无效。

而且,只有在字段已经被判定为无效的情况下,您才可以修改自定义错误。这意味着即使您在同一个处理程序中清除消息,表单仍然不会被提交。

实现您的目标的更好方法是在该字段的 change 事件处理程序中监视该字段并在那里设置自定义消息:

document.getElementById('UserName').addEventListener('change', function (ev) {
    const input = ev.target;
    if (input.validity.patternMismatch) {
        input.setCustomValidity("Usernames cannot contain the @ symbol");
    } else {
        input.setCustomValidity("");
    }
}, false);
<form onsubmit="event.preventDefault(); alert('Form submitted');" action="post">
    <!--pattern regex prohibits use of the @ symbol-->
    <input id="UserName" type="text" pattern="^((?!@).)*$" required />
    <button type="submit">Submit</button>
</form>