【问题标题】:Why is jQuery select event listener triggering multiple times?为什么 jQuery 选择事件侦听器会触发多次?
【发布时间】:2016-07-17 00:09:35
【问题描述】:

请在 Google Chrome 浏览器中运行this sample

堆栈片段

$(function() {
  $(":input").select(function() {
    $("div").text("Something was selected").show().fadeOut(1000);
    alert("Selected");
  });
  $("button").click(function() {
    $(":input").select();
  });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<button>Click To Select</button>
<input type="text" value="Some text">
<div></div>

这里为什么 jQuery 选择事件监听器会触发多次?有谁知道这背后的原因?是否有任何不使用超时的解决方法?

【问题讨论】:

  • jsfiddle.net/arunpjohny/3qkvr5zq/2 - 一旦被select() 调用在内部触发,但在退出click 处理程序后,它会被调用两次,我认为这是由渲染操作完成的

标签: javascript jquery html google-chrome dom


【解决方案1】:

$(":input") 选择器也在选择按钮,因此它会导致递归。要么只使用$("input"),要么使用$(":input:not(button)")

我注意到当三个事件被触发时,第一个没有originalEvent 属性,所以我们绝对可以将其关闭,而后两个具有非常相似(但不相同)的时间戳。您可以将最后一个时间戳存储在某个变量中,并在事件侦听器中将其与事件的时间戳进行比较。如果这两者的取整值相同,则可以关闭此事件。

$(function() {
  var lastTimeStamp;
  $("input").select(function(event) {
    if (!event.originalEvent ||
        lastTimeStamp === Math.round(event.timeStamp)) return;
    lastTimeStamp = Math.round(event.timeStamp);
    $("div").text("Something was selected").show().fadeOut(1000);
    alert("Selected");
  });
  $("button").click(function() {
    $("input").select();
  });
});

updated JS Fiddle

【讨论】:

    【解决方案2】:

    问题似乎是以下几种情况的组合:

    • :input 选择器获取inputbutton,因此触发了多个事件。
    • 即使仅使用 input 作为选择器,也会在相关元素上触发一些奇怪的事件传播,从而多次引发 select 事件处理程序。

    为避免上述两种情况,请使用input 作为选择器,并在事件处理程序中使用preventDefault()stopPropagation() 也可能是必需的,具体取决于您的 HTML 结构。

    $(function() {
        $('input').select(function(e) {
            // e.stopPropagation(); // optional
            e.preventDefault();
            $('#message').text("Something was selected").show().fadeOut(1000);
            console.log('Selected');
        });
    
        $('button').click(function() {
            $('input').select();
        });
    });
    

    Working example

    【讨论】:

    • 错误的选择器确实是问题的根源,另一个问题只存在于 Chrome 而不是 FF & IE。
    • @RoryMcCrossan e.preventDefault() 将阻止选择文本。
    【解决方案3】:

    更新:我们都被愚弄了。 select() 函数需要一个阻止默认值。

    Rory McCrossan 想通了。干得好伙计。

    顺便说一句,我不确定 select() 究竟有什么好处!像 focus() 或 on('focus',) 这样的东西可能更有意义。但是不确定上下文是什么。以下仍然是:

    为什么要浪费时间使用可能会改变的通用标签/类型选择器?使用一个 ID,只选择你想要的那个。

    如果要检测多个,请使用一个类。如果您想使用多个,但要弄清楚您单击了哪个,请使用一个类和一个 ID。与类绑定,并使用$this.attr('id')进行识别。

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
    <button>Click To Select</button>
    <input type="text" value="Some text" id="pick-me">
    <div></div>
    
    $(function() {
      $("#pick-me").select(function(event) {
        event.preventDefault();
        $("div").text("Something was selected").show().fadeOut(1000);
        alert("Selected");
      });
      $("button").click(function() {
        $("#pick-me").select();
      });
    });
    

    【讨论】:

    • 在最新的 Chrome 上仍然会触发 3 次,请参阅 JS Fiddle
    • @Gothdo 哈哈,你是对的。奇怪。现在要解决这个问题!
    • 是的,这是需要 preventDefault 的事件。我什至不确定我是否曾经在输入上使用过'select()'方法。我总是使用焦点或类似的东西。
    • @TimOgilvy 如果我们使用event.preventDefault();,它将不允许通过按钮单击选择文本。
    • $e.focus() 将焦点放在 $e 元素上。 $e.select() 将焦点放在 $e 元素上并选择所有内容。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-23
    • 2011-07-28
    • 2011-03-03
    • 1970-01-01
    相关资源
    最近更新 更多