模糊事件会阻止点击事件的工作吗?

81

似乎失焦事件会阻止点击事件处理程序的工作?我有一个组合框,选项只在文本字段获得焦点时才会出现。选择一个选项链接应该导致事件发生。

我在这里提供了一个示例:http://jsfiddle.net/uXq5p/6/

复现步骤:

  1. 选择文本框
  2. 链接出现
  3. 单击链接
  4. 触发失焦事件,链接消失
  5. 没有其他反应。

期望行为:

在第5步完成后,失焦事件发生后,点击事件也应该触发。如何实现这一点?

更新:

经过一段时间的尝试,似乎有人极力防止失焦事件使被点击的元素无法再次点击。

例如:

$('#ShippingGroupListWrapper').css('left','-20px');

功能正常,但是

$('#ShippingGroupListWrapper').css('left','-2000px');

防止点击事件发生。

这似乎是Firefox的一个错误,因为使元素无法被点击应该可以防止未来的点击事件,但不应该取消已经发生的点击事件。

其他阻止处理点击事件的事情:

$('#ShippingGroupListWrapper').css('z-index','-20');
$('#ShippingGroupListWrapper').css('display','none');
$('#ShippingGroupListWrapper').css('visibility','hidden');
$('#ShippingGroupListWrapper').css('opacity','.5');

我在这个网站上找到了几个类似的问题。似乎有两种解决方案:

  1. 使用延迟。这种方法不好,因为它会在隐藏和单击事件处理程序之间创建竞态条件。而且这样做很草率。

  2. 使用 mousedown 事件。但这也不是一个很好的解决方案,因为对于链接来说,click 才是正确的事件。从用户体验角度来看,mousedown 的行为是反直觉的,特别是在释放按钮之前无法通过将鼠标移动到元素外部来取消单击。

我能想出几个更多的解决方案。

3.在链接上使用 mouseovermouseout 来启用/禁用字段的模糊事件。这种方法无法与键盘 tab 键一起使用,因为鼠标没有参与其中。

4.最好的解决方案应该是:

$('#ShippingGroup').blur(function()
{
   if($(document.activeElement) == $('.ShippingGroupLinkList'))
      return; // The element that now has focus is a link, do nothing
   $('#ShippingGroupListWrapper').css('display','none'); // hide it.
}

不幸的是,$(document.activeElement) 似乎总是返回 body 元素,而不是被点击的元素。但也许有一个可靠的方法可以知道当前具有焦点的元素或者哪个元素导致了模糊(不是模糊的元素)从模糊处理程序内部。此外,除了 mousedown 事件之外,还有其他事件会在模糊事件之前触发吗?


4
问题在于模糊事件在点击事件之前触发。由于模糊隐藏了那些元素,所以你最终什么也没点击到。 - vcsjones
1
我不确定隐藏是否是问题所在。我尝试将不透明度设置为50%而不是隐藏它们,但点击事件仍然不会发生。请参见jsfiddle.net/75sgt/1。 - Nick
经过进一步的实验,发现新的不可点击性会对已经被点击的元素进行“反向点击”。请参见我上面的更新。 - Nick
8个回答

101

click事件在blur之后触发,所以链接被隐藏了。使用mousedown代替click,这样它就可以工作了。

$('.ShippingGroupLinkList').live("mousedown", function(e) {
    alert('You wont see me if your cursor was in the text box');
});

另一种选择是在blur事件触发前添加一些延迟来隐藏链接。你可以选择采用哪种方法。

示例


1
使用延迟是危险的。应该坚持使用mousedown。 - Marshall
1
是的,即使是我也会始终选择使用 mousedown 而不是使用脏延迟逻辑。 - ShankarSangoli
我尝试了(http://jsfiddle.net/75sgt/1/) 50%的不透明度,但它没有起作用。我认为问题不是元素不可见,而是在失焦后没有执行点击事件。 - Nick
9
还要注意:这也会在右键单击时触发,而通常不会触发点击事件。你的处理程序应该包括 if (e.which === 1) { } - Brad
4
请注意,你确定这个方法适用于不使用鼠标来激活链接或聚焦/失焦元素的用户吗? - Michael Scheper
显示剩余5条评论

5
你可以尝试使用mousedown事件代替click事件。
$('.ShippingGroupLinkList').live("mousedown", function(e) {
    alert('You wont see me if your cursor was in the text box');
});

这显然不是最好的解决方案,因为用户实现mousedown事件的方式与click事件不同。不幸的是,blur事件也会取消mouseup事件。


我认为mousedown会触发blur。另一种方法是在mousedown上阻止传播并在mouseup上执行您的操作。 - Nate Symer

4
执行应该在单击mousedown上发生的动作是不好的用户体验。相反,一个点击实际上是由mousedown和mouseup组成的。
因此,在mousedown处理程序中停止mousedown事件的传播,并在mouseup处理程序中执行操作。
以下是ReactJS示例:
<a onMouseDown={e => e.preventDefault()}
   onMouseUp={() => alert("CLICK")}>
   Click me!
</a>

2

4.The best solution would be something like:

$('#ShippingGroup').blur(function()
{
   if($(document.activeElement) == $('.ShippingGroupLinkList'))
      return; // The element that now has focus is a link, do nothing
   $('#ShippingGroupListWrapper').css('display','none'); // hide it.
}

Unfortunately, $(document.activeElement) seems to always return the body element, not the one that was clicked. But maybe if there was a reliable way to know either 1. which element now has focus or two, which element caused the blur (not which element is blurring) from within the blur handler.

您可能正在寻找的是 e.relatedTarget。因此,当单击链接时,e.relatedTarget 应该被链接元素填充,因此在您的模糊处理程序中,如果所单击的元素位于容器内(或直接与链接进行比较),则可以选择不隐藏容器。请注意保留 HTML 标签。
$('#ShippingGroup').blur(function(e)
{
   if(!e.relatedTarget || !e.currentTarget.contains(e.relatedTarget)) {
   // Alt: (!e.relatedTarget || $(e.relatedTarget) == $('.ShippingGroupLinkList'))

       $('#ShippingGroupListWrapper').css('display','none'); // hide it.
   }
}

(relatedTarget可能在旧版浏览器中不支持blur事件,但它似乎在最新版本的Chrome、Firefox和Safari中可以使用)


好主意,但不幸的是这并不起作用:仅当新焦点元素是可获焦元素(例如链接或input/select等)时,才会设置relatedTarget。如果您点击某个div等,则不会设置它。 - Mr. TA

1
如果this.menuTarget.classList.add("hidden")是隐藏可点击菜单的模糊行为,那么在调用它之前等待100毫秒后我成功了。
setTimeout(() => {
  this.menuTarget.classList.add()
}, 100)

这允许在隐藏之前对menuTarget DOM进行单击事件处理。


延迟对我也起作用了。因为我使用的是routerLink,而不是onclick... - mamashare

0

在使用jQuery模糊、点击处理程序时,我遇到了类似的问题,其中我有一个输入名称字段和一个保存按钮。使用模糊事件将名称填充到标题占位符中。但是当我们在输入名称后立即单击保存时,只会触发模糊事件,而忽略保存按钮的单击事件。

我使用的技巧是利用我们从模糊事件中获得的事件对象,并检查event.relatedTarget。

以下是对我有效的代码:

$("#inputName").blur(function (event) {
        title = event.target.value;
        //since blur stops an immediate click event from firing - Firing click event here
        if (event.relatedTarget ? event.relatedTarget.id == "btnSave" : false) {
            saveBtn();
        }
    });

$("#btnSave").click(SaveBtn)

正如在本主题中已经讨论的那样 - 当模糊事件同时触发时,它会阻止点击事件。因此,我为保存按钮注册了一个点击事件,调用一个函数,当模糊事件的相关目标是保存按钮时,也会调用该函数以弥补点击事件未触发的情况。 注意:在使用本地onclick和onblur处理程序时没有注意到这个问题 - 在HTML中进行了测试。


0

我知道这是一个晚回复,但我遇到了同样的问题,很多解决方案在我的情况下并没有真正起作用。 mousedown 在表单中不起作用,它会导致提交按钮上的回车键功能发生变化。相反,您可以在 mousedown 中设置一个变量 _mouseclick 为 true,在 blur 中检查它,并且如果它为 true,则使用 preventDefault()。然后,在 mouseup 中将变量设置为 false。除非有人能想到任何问题,否则我没有看到任何问题。


0
晚到派对了,但如果有一个特定的元素被点击,你可以使用e.relatedTarget来识别它,然后手动调用应该在点击时发生的函数。
onBlur (e) {
  // your on blur code
  if (e.relatedTarget.className.includes('button-class')) this.buttonAction()
},

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接