为啥 jQuery 选择事件侦听器会触发多次?
Posted
技术标签:
【中文标题】为啥 jQuery 选择事件侦听器会触发多次?【英文标题】: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
处理程序后,它会被调用两次,我认为这是由渲染操作完成的
【参考方案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
选择器获取input
和button
,因此触发了多个事件。
即使仅使用 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。 @RoryMcCrossane.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 元素上并选择所有内容。以上是关于为啥 jQuery 选择事件侦听器会触发多次?的主要内容,如果未能解决你的问题,请参考以下文章
为啥 jQuery 单击事件侦听器未在 WooCommerce 按钮上注册?
使用名称中的点调度 CustomEvent 不会触发 jQuery.on() 事件侦听器
丢弃 child 会触发 parent 的“drop”事件侦听器。我想用特定于子的“drop”覆盖该事件侦听器
Jquery 事件侦听器不处理附加元素(他们应该,不是吗?)