【问题标题】:mouseenter event called twice even after stopPropagation即使在 stopPropagation 之后也调用了两次 mouseenter 事件
【发布时间】:2011-10-16 20:16:57
【问题描述】:

我是 jquery 的新手,现在面临一个奇怪的问题。我成功地将其范围缩小到两次调用 mouseenter 事件的事实:一次用于包含 div(这是我的意图),再次用于此 div 中的元素(不好)。我尝试使用“return false”和“stopPropagation”,但它似乎不起作用。 这是代码:

<!-- JS files (order matters!) -->
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.js"></script>


<script type="text/javascript">
$(function (){
    $(".testDiv").hover(
    function(e) /* IN */ {
        $(this).data("htmlBackup", $(this).html());
        $(this).html("TEST 123");
        e.stopPropagation();
        return false;
    }, function(e) /* OUT */ {
        $(this).html($(this).data("htmlBackup"));
        e.stopPropagation();
        return false;
    });
});         
</script>

<!-- this one works -->
<div class="testDiv" style="border: solid">ORIG HTML</div>

<br /> <br /> <br />

<!-- this doesn't work -->
<div class="testDiv" style="border: solid"> <p style="border: solid">ORIG HTML</p></div>

你也可以在这里看到:http://jsfiddle.net/rFqyP/3/

任何帮助将不胜感激!

【问题讨论】:

标签: javascript html javascript-events jquery


【解决方案1】:

发生的情况是mouseenter 事件连续触发两次(您可以通过一些console.log 调用轻松测试这一点)。这是有问题的,因为它会更改元素的 html(并使其只是“测试”字符串),然后在第二次连续运行时,它将获取 html 并将其保存到元素的数据中。但是由于没有触发 mouseleave 事件,如上所述,html 是“测试”字符串,所以现在它将 that 保存到元素数据中。

之后,mouseentermouseleave 事件继续正常触发,但元素的 html 及其数据都具有相同的“测试”字符串,因此不会改变。

mouseenter 连续触发两次的原因是因为边界。 div 的尺寸发生变化,因此会发生以下一系列事件:

  1. mouseenter(div变细了)
  2. mouseleave(div 变粗会导致几乎自动出现mouseenter
  3. mouseenter 如 2 所述,因为即使鼠标离开了 div,div 也展开了,所以鼠标进入了。 但是自从mouseenter被触发后,div到了“test”字符串,变得更细了,所以现在鼠标已经超出了div的边界,但是没有触发mouseleave。李>
  4. 下次我将鼠标悬停在 div 上时,mouseenter 将再次触发

您可以看到这种情况正在发生,例如,如果您用鼠标缓慢输入上述某些事件并没有发生,它实际上会按预期工作。

顺便说一句,我不认为交换 html 内容是最好的主意。如果你想切换,我建议hide()show()。首先,这节省了事件处理程序,并且更直观。你对隐藏东西感兴趣,而不是序列化和保存。

【讨论】:

  • 正确。他必须检查被调用者元素是否为 div。还有为什么 p 调用事件,即使它没有附加到?
  • 我得出了同样的结论。
  • @Umair Ashraf:p 元素根本不会导致任何事件,只是div 的大小变化会导致额外事件。您可以通过记录元素的标签名称来查看这一点:jsfiddle.net/rFqyP/14
  • 将“this.tagName”更改为“e.target”,它也会显示段落。
  • @Umair Ashraf:您必须区分事件和事件处理程序。即使没有事件处理程序,事件也总是发生,因此p 元素会发生mouseover 事件并冒泡到有事件处理程序的div 元素。 target 属性是事件发生的元素,而不是处理它的元素。
【解决方案2】:

您可以通过使用标志来防止代码卡住,这样您就可以检测到何时收到双重mouseenter事件:

$(function(){

  var inside = false;

  $(".testDiv").hover(
    function(e) /* IN */ {
      if (!inside) {
        inside = true;
        $(this).data("htmlBackup", $(this).html());
        $(this).html("TEST 123");
      }
    }, function(e) /* OUT */ {
      inside = false;
      $(this).html($(this).data("htmlBackup"));
    }
  );

});

http://jsfiddle.net/rFqyP/16/

但这并不能解决大小差异的问题。当您通过从底部边框移出离开元素时,它会增长并导致mouseenter 事件,该事件再次更改大小以使鼠标在外面但不会导致mouseleave 事件,使元素看起来像鼠标还在徘徊。

p 元素中删除边框完全解决了问题,不需要标志,因为它是导致大小差异的边框。

【讨论】:

  • 看来是这样做的。我希望有一个更优雅的解决方案,但我想没有。我非常感谢您提供的所有帮助。我也想借此机会感谢其他所有人。
  • 最后一条评论 - 我还用 'if (event.target == this) {..}' 包裹了悬停回调,以确保不会有任何内部“竞赛” " 离开内部元素时的条件。希望这会对遇到类似问题的人有所帮助。
【解决方案3】:

我认为第二个不起作用,因为 html 不同。如果您使用相同的 html,则根本不需要 stopPropagationreturn false。看小提琴:http://jsfiddle.net/aC3TG/1/

$(function (){
    $(".testDiv").hover(
    function(e) /* IN */ {
        $(this).data("htmlBackup", $(this).html());
        $(this).html("TEST 123");
    }, function(e) /* OUT */ {
        $(this).html($(this).data("htmlBackup"));

    });
});         

【讨论】:

  • 他在 div 中有“p”标签,它也在触发它的事件并导致问题。我认为简单地删除“p”标签不是解决方案
  • 是的,但是在元素悬停在 div 上后 p 标签会被删除:在这种情况下,我会更改 html,我看不出保持它的意义
  • 不,p 标签没有任何事件处理程序,因此导致问题的不是它的优先级。从p 元素中删除边框可以解决问题,因为这就是造成大小差异的原因。
  • @Nicola:这只是一个演示我的问题的示例代码。我真正的 html 是一个 div,其中包含几个 'p's 和 'img's 以及其他 'div's。而且这些元素也有边界和固定大小,因此改变这不是一种选择。
【解决方案4】:

我看到的问题(调试后)是。你里面有 div 和 p 所以...

当您将鼠标悬停在具有 p 的 div 上时,首先会触发 div "mouseover" 事件,该事件会存储包括 p 标签在内的整个 html。

但在将此 html 写回 div 之前,会触发“p”鼠标悬停,它将您的数据替换为文本而不是 html。

然后你的文本最终被写入 div。

【讨论】:

  • 不,这是不正确的。 p 元素的 mouseover 事件没有事件处理程序。您可以通过在事件处理程序中记录标签名称来检查这一点:jsfiddle.net/rFqyP/14
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-11
  • 1970-01-01
  • 2011-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多