Javascript 修改DOM时单击事件丢失

Javascript 修改DOM时单击事件丢失,javascript,html,Javascript,Html,有两个input元素隐藏在模糊中。问题是,如果在DOM中隐藏元素之后的元素上单击,则导致模糊的单击事件将丢失 如果单击的图元位于模糊图元之前,则它将按预期工作 这个简单的片段演示了: <html> <script src="./jquery.min.js" ></script> <script type="text/javascript"> $(document).ready(function() { $('input').blur

有两个
input
元素隐藏在模糊中。问题是,如果在DOM中隐藏元素之后的元素上单击,则导致模糊的单击事件将丢失

如果单击的图元位于模糊图元之前,则它将按预期工作

这个简单的片段演示了:

<html>
<script src="./jquery.min.js" ></script>
<script type="text/javascript">
$(document).ready(function() {
        $('input').blur(function(e) {
            console.log('blurred');
            $(this).hide();
        });

        $('.a').click(function() {
            console.log('div clicked');
        });

        $(document).click(function() {
            console.log('doc clicked');
        });
    });
</script>
<body>
<div id="div1">
<div class="a"><input /></div>
<div class="a"><input /></div>
</div>
</body>
</html>

$(文档).ready(函数(){
$('input').blur(函数(e){
console.log(“模糊”);
$(this.hide();
});
$('.a')。单击(函数(){
log('div clicked');
});
$(文档)。单击(函数(){
console.log('doc clicked');
});
});
如果单击底部输入,则单击顶部输入,它将按预期工作-“模糊”打印,然后单击“div”,然后单击“doc”,并且隐藏底部输入

如果单击顶部输入,则底部、顶部输入将隐藏,只有“模糊”打印,并且单击事件无法在任何地方处理

如果对
hide
的调用被注释掉,它也会按预期工作

使用
.live
没有什么区别

我能想出解决这个问题的办法,但没有一个是很好的。有没有想过为什么输入的顺序很重要,或者更好的解决方案

谢谢。

事件对象的srcElement属性是IE事件模型特有的。jQuery通过添加
e.target
来“规范化”事件对象,其中不存在
e.srcement

    // Fix target property, if necessary (#1925, IE 6/7/8 & Safari2)
    if ( !event.target ) {
        event.target = originalEvent.srcElement || document;
    }
因此,在这一行中:

>  $(e.srcElement).hide();
'e.srcElement`返回未定义的,语句不执行任何操作

修复方法是将
e.src元素
更改为
e.target
,或者改用
this

请注意,在侦听器中,
this
是调用侦听器的元素,而
target
是从中调度原始事件的元素。因此,它们可能引用或不引用同一元素

在模糊侦听器中,
this==event.target
,但不在单击侦听器中

顺便说一句,将调用链接在一起被认为是一种不好的做法,因为这样会使错误(像这样的错误)难以发现和调试。拥有一个默默忽略这些错误的图书馆会使它变得更加困难,而应该考虑:

    $('input').blur(function(e) {

        if (e.srcElement) {
          $(e.srcElement).hide();

        } else {
          // No e.srcElement? what now!!
        }
    });

防御性编码实践对web开发人员来说已经过时,但它们更可靠,更容易调试。

好吧,好吧,这只是我们一起愚蠢而已

看看当你从上到下点击时发生了什么

顶部有焦点。当您单击位于其下方的第二个输入时,模糊事件在单击事件在第二个div上注册之前触发

所发生的事情是,您正在点击第二个输入,以使其成为焦点。由于事件从单击的目标(第二个输入)冒出,因此它获得焦点。但由于第一个“输入模糊”事件首先触发,它会将顶部div的高度降低到0,并立即将第二个div向上移动,超出当前鼠标位置的范围。因此,第二个div上的click事件永远不会发生,因为在这之前div已经被移走了

您可以在这个jsfiddle中看到原因。我添加了
元素以保持div高度,即使在它们的输入被隐藏之后也是如此。如果您查看控制台,您将看到它按预期工作

Firefox工作的原因是它处理事件的时间有点不同

忽略我下面的原始答案:

这是非常奇怪的行为。我已经在Mac OS 10.7上的Chrome和Safari中验证了您的结果。不过,Firefox12.0的工作原理与预期一致

如果在500ms设置超时内进行模糊,则效果与预期一致。尽管我认为父div上的事件仍在被删除

我这里有一个JSFIDLE


我强烈建议将此作为一个bug提交到jQuery开发站点。这看起来像是blur()的一个bug。

我认为这并不能解释事件被吞没的原因。但如果输入的位置不是问题,则可以改为更改可见性

$('input').blur(function(e) {
    console.log('blurred');
    $(this).css('visibility', 'hidden');
});

当然,已修复,但不会改变行为。@RobG,这取决于他的doctype。XHTML有用于输入的结束标记HTML doctype do not。这没关系-感谢您的回复,您对问题的事件处理方面有什么想法吗?DOM是如何修改的?通过隐藏
输入
。我想这实际上并不算是修改DOM,最初我删除了
输入
。我理解这一点,但这并没有改变从未调用单击处理程序的事实。我不认为是这样,因为
输入
总是正确隐藏。我发现我没有在原始问题中解释这一点,我的错误。你编辑了原始代码,按照建议将
e.srceelement
更改为
this
,因此它现在当然“起作用”。实际上行为没有变化,这可能是因为Chrome支持IE事件模型和W3C模型,所以它有
event.srcElement
。Opera可能也支持它,但我不认为这是jquery的问题。如果使用javascript的onblur,也会发生相同的行为。这确实是一种奇怪的行为……罗伯,看看我上面修改过的答案。它真的是这样工作的吗?我希望事件是由家长而不是屏幕位置引起的。另外,为什么在单击发生时,单击事件会消失,而不是发生在光标下方的任何元素上?在这种情况下,事件至少会被记录在案。我不同意它是如何运作的。Firefox似乎处理得很好。但是,通过使div具有与演示中相同的高度,它起了作用。经过更多的实验,我认为你说得很对-单击会导致输入模糊,处理程序运行,然后根据单击的原始屏幕位置重新计算单击。如果原来是c