jQuery 验证:检测基础点击而不是模糊

jQuery Validate: Detecting underlying click instead of blur

我有一个在 Bootbox 中创建的表单(它本身是 Bootstrap 模式顶部的一个层)。创建后,我调用

$('#myForm').validate()

就可以了。

该行为的理想部分是,现在当用户在表单中切换时,他们可以立即看到他们搞砸了其中一个字段的反馈。在点击 "tab" 或点击其他地方之前输入了非电子邮件地址?警告和错误信息。太棒了!

但不受欢迎的是模糊吞噬了其他事件。因此,如果用户选择点击 "cancel"(完全清楚表单无效),则不会听到取消点击,并且不会触发其处理程序。第二次单击(现在焦点完全不在窗体上)并按预期取消触发。我不希望用户必须点击两次。

我看到了一种完全禁用模糊的技术,但随后上述理想的行为就丢失了,我也不希望这样。理想情况下,"well, I blurred, but I also know what the user was clicking" 就是我所追求的。

[编辑添加:]

我注意到这令人困惑,所以让我尝试用不同的方法来解决这个问题:是否可以处理一个表单(已经 .validate() 调用了它),然后单击整个页面上的任何其他可单击项目并成功触发其单击处理程序?

[再次编辑:]

根据 Sparky 的演示,我连接了一条警告,以在模糊输入下方显示。因此,要查看实际问题,请启动此 fiddle:https://jsfiddle.net/bd1fhpu3/

然后在单击 "just a button" 之前单击其中一个输入字段。单击 "just a button" 的上条以确保在释放鼠标按钮时警告标签已将其推出光标热点。

总之,这正好说明了问题所在。解决它可能不再在问题的范围内,但它似乎值得分享,以防其他人遇到这个问题。要解决,我需要将 Bootbox 的点击事件重写为 mousedown 事件而不是点击(然后你不需要按下和释放),或者我可以 "Band-Aid"(tm) 通过避免重定位来解决按钮。也许是一个高度足以容纳表单和任何可能的警告的静态高度对话框。绝对有点像这样的 "hack",因为您永远不知道您以后是否会做其他事情而使问题再次出现。但这将是一个快速简单的临时修复。

您不能使用内置的 onfocuout 函数,因为 JavaScript 不可能知道聚焦到另一个字段和聚焦到取消按钮之间的区别。

您必须完全禁用 onfocusout 并编写一些自定义事件处理程序。

你的代码很少,所以我的回答会很笼统。

$('#myForm').validate({
    // other options here
    onfocusout: false;   // disable default blur event
});

然后编写一个事件处理程序,当他们聚焦到 input 时以编程方式触发表单验证,并且当他们聚焦到任何东西时什么都不做,比如取消按钮。

$('#myForm input').on('focus', function() {
    $('#myForm').valid();  // trigger validation on the form
});

但是,这将触发对整个表单的验证。如果您只想在一个失去焦点的字段上触发验证,那么您又回到了原点,因为该事件只知道失去焦点,而不是它的去向。

为了后代,这里有一个"answer"。也许有一天它会对某人有所帮助;你永远不知道。

没有正在运行的代码 "incorrectly",因此实际上没有提供修复程序或代码示例。事情是这样的:

  1. 用户在字段中处于焦点
  2. 用户按下鼠标按钮(但尚未发生释放动作)
  3. Blur 事件触发,导致表单错误警告出现在字段下方。这也具有将 "cancel" 按钮向下推到屏幕的 Y 轴
  4. 的净效果
  5. 用户释放鼠标按钮,这通常会完成 "click" 处理程序。

但是,在 #4 中,由于 "cancel" 按钮不再位于光标下,绑定到该按钮的点击事件侦听器不会触发。

该演示,只要它存在于 Internet 上,就会在下面的评论中显示。但是,提供代码示例是没有意义的。等demo死了,我就把评论删了。


到目前为止我选择不执行的可能步骤(workarounds/hacks):

  1. 修改对话框,使按钮在 mousedown 事件触发时不移动,这意味着 "click" 事件已成功完成
  2. 提供用 mousedown 事件替换按钮上的单击事件的自定义代码。但是,这会导致相当常见的 UI 惯例丢失
  3. 强制用户按 ESC 键取消,而不是单击按钮
  4. [来自 Tieson T. via comment] 如果您可以在错误消息上使用一些自定义样式,一种可能的选择是使用 visibility: none 而不是 display: none 隐藏它们。前者会隐藏文本,但仍会保留文本的垂直 space,而后者不会(因此您的模式正在扩展)。这将防止按钮在 focusout 事件期间发生移动。你最终会得到额外的白色space,但你可以通过移除表单组的底部边距来消除其中的一些(假设你正在使用它)

我确定还有其他解决方法,但这是一个起点。