【问题标题】:mouseup, click events and DOM manipulationsmouseup、点击事件和 DOM 操作
【发布时间】:2016-08-10 16:50:30
【问题描述】:

堆垛机,

我有一个奇怪的案例。有一个容器元素,其中包含其他一些具有“可点击”类的元素。可点击的“点击”事件侦听器使用委托附加到容器。

<input type="text"/>
<div class="container">
    <div class="clickable">Click</div>
</div>

$container.on('click', '.clickable', incrementCounter);

容器外还有一个输入元素。在“更改”事件中,容器的内容在下一个事件循环轮次中被替换为相同的内容(使用 $container.html())(现实:-)。

$input.on('change', function() {
    setTimeout(function() {
        $container.html('<div class="clickable">Click</div>');
    }, 0);
});

现在是这样:在输入字段中输入一些内容(不要单击任何位置或按 Enter)。然后立即点击可点击。

会发生什么:'change' 事件导致容器在下一个事件循环轮次中重新渲染,并且永远不会生成 'click' 事件。

可以通过将“click”事件替换为“mouseup”来解决。

问题:为什么会有这样的差异?

plunk

【问题讨论】:

  • 请检查答案并接受或说它是否不够好。
  • 谢谢@AndreiToutoukine :) 对答案的投票也将不胜感激!

标签: jquery click event-delegation mouseup


【解决方案1】:

您遇到了blurclick 事件之间的竞争条件。
click 事件实际上是同一元素上的 mousedownmouseup 事件的组合。

如果你改变输入然后点击你的容器,你拥有的事件是:

mousedown (on row)
blur (on input)
mouse up (on row)

由于鼠标按下和鼠标抬起事件受到干扰(被模糊),您不会收到 click 事件。

我为相关事件添加了console.log,你可以查看这个sn-p:

$(function() {
  var rowHtml = '<div class="row">Click</div>';
  
  var $rowsContainer = $('.rows-container');
  var $counter = $('.counter');
  var $blinker = $('.blinker');
  var $input = $('input[type=text]');
  
  $input.on('change', blink);
  $rowsContainer.on('mousedown', function(e) {
    console.log('mousedown', e.target);
  });
  $rowsContainer.on('mouseup', function(e) {
    console.log('mouseup', e.target);
  });
  $rowsContainer.on('click', function(e) {
    console.log('click', e.target);
  });
  $input.on('blur', function(e) {
    console.log('blur', e.target);
  });
  
  $rowsContainer.on('click', '.row', incrementCounter);
  
  // this works as expected
  //$rowsContainer.on('mouseup', '.row', incrementCounter);
  
  function incrementCounter() {
    var oldValue = parseInt($counter.text(), 10) || 0;
    $counter.text(1 + oldValue);
  }
  
  function blink() {
    setTimeout(function() {
      $rowsContainer.html(rowHtml);
    }, 0)

    $blinker.html('☼');
    
    setTimeout(function() {
      $blinker.html('&nbsp;');
    }, 300);
  }
});
.counter,
.blinker {
  display: inline-block;
  width: 1.2em;
}
.rows-container {
  border: 1px dotted #ccc;
  margin: 1em;padding: 2em;
}
.row {
  padding: 1em;
  background-color: #eef;
}
p {
  font-size: 12px;
  line-height: 12px;
}
<script data-require="jquery@2.1.4" data-semver="2.1.4" src="https://code.jquery.com/jquery-2.1.4.js"></script>
<h1>Click vs. mouseup whith DOM manipulation</h1>
<p>On the input field change event a little sun shortly appears on the right
  and the content of the "Click" parent is redrawn with the identical content.
</p>
<p>Clicking on "Click" increments the counter. It works by delegation of the
  event handling to the "Click" container.
</p>
<p>Try to enter something in the text field and trigger the "change" event
  by clicking on "Click". Sun appears but counter is unchanged.</p>
<p>When listening to 'mouseup' event instead of the 'click' everything works.</p>

<h2>Why?</h2>
<span class="counter">0</span>
<span class="blinker">&nbsp;</span>
<input type="text" />
<div class="rows-container">
  <div class="row">Click</div>
</div>

您可以使用此示例了解 mousedown/mouseup/click 事件的具体工作原理。

  1. 单击容器(不离开鼠标),将鼠标拖到容器外,然后离开鼠标。您会看到容器上有一个mousedown,而其他一些元素(如body)上有一个mouseup,但没有click 事件。
  2. 单击容器(不离开鼠标),将鼠标拖动到容器内,然后离开鼠标。您会看到现在您确实有一个click 事件。

【讨论】:

    猜你喜欢
    • 2023-01-24
    • 2016-03-29
    • 2017-07-15
    • 1970-01-01
    • 2022-11-23
    • 1970-01-01
    • 2015-03-16
    • 1970-01-01
    • 2011-01-07
    相关资源
    最近更新 更多