单击标签内的文本时,如何使函数不会触发两次。
如果我使用event.preventDefault(),那么选中复选框的基本浏览器功能也将停止工作。
const label = document.querySelector('.parent');
label.addEventListener('click', handleLabelClick);
function handleLabelClick(event) {
console.log('Clicked')
}
<div class="parent">
<label for="option1">
<span>Select me</span>
<input id="option1" type="checkbox">
</label>
</div>
据我了解,您希望点击.parent
元素来触发点击处理程序,但您不希望该处理程序针对与.parent
中的复选框或其标签相关的点击而触发。
有两种方法可以做到:
label
添加一个调用stopPropagation
的处理程序,或者label
传递这是方法#1:
const parent = document.querySelector('.parent');
parent.addEventListener('click', handleLabelClick);
// Stop clicks in the label or checkbox from propagating to parent
parent.querySelector("label").addEventListener("click", function(event) {
event.stopPropagation();
});
function handleLabelClick(event) {
console.log('Clicked');
}
.parent {
border: 1px solid #ddd;
}
<div class="parent">
<label for="option1">
<span>Select me</span>
<input id="option1" type="checkbox">
</label>
</div>
这是方法#2:
const parent = document.querySelector('.parent');
parent.addEventListener('click', handleLabelClick);
function handleLabelClick(event) {
const label = event.target.closest("label");
if (label && this.contains(label)) {
// Ignore this click
return;
}
console.log('Clicked');
}
.parent {
border: 1px solid #ddd;
}
<div class="parent">
<label for="option1">
<span>Select me</span>
<input id="option1" type="checkbox">
</label>
</div>
这是标准(不幸)浏览器行为。
属性for
将<label>
分配给<input>
,因此当单击<label>
元素时,浏览器将在您实际点击后立即模拟<input>
元素上的单击。
这允许文本<input>
的焦点,无线电<input>
的切换,或复选框<input
>的切换。
但是对于不幸的部分,这也导致两个元素都发送click事件。如果您正在收听父元素的点击,这意味着您将收到两次“人工互动”。一次来自<input>
,一次来自“点击元素”。
对于那些想知道<input>
could be inside <label>
元素的人来说,你可以获得更少的造型可能性,但是你可以在复选框和文本之间点击。
你在<span>
里面放置<input>
和<label>
实际上创造了一个不错的测试用例。
尝试从左到右点击;
在文本中,您将收到SPAN + INPUT事件,
在文本和复选框之间,您将获得LABEL + INPUT事件,
在复选框上直接只有INPUT事件,
然后更右,只有DIV事件。 (因为DIV是一个块元素并且一直向右移动)
一个解决方案是只听<input>
元素事件,但是你不会捕获<div>
点击,你也不能把<div>
放在<label>
。
最简单的方法是忽略qazxsw poi上的点击以及qazxsw poi中除qazxsw poi之外的所有可点击元素。在这种情况下<label>
。
<label>
<input>
*)在我的例子中,我将类名parent更改为包含div元素和包含div元素的变量名标签到elWrapper,因为parent和label是关键字,并且它们用于其他方法可能会令人困惑。
来自@ T.J的解决方案。导致来自<span>
的事件及其内部的一切都被忽略了。要触发事件,您需要单击const elWrapper = document.querySelector('.wrapper');
elWrapper.addEventListener('click', handleLabelClick);
function handleLabelClick(event) {
console.log('Event received from tagName: '+event.target.tagName);
if (event.target.tagName === 'LABEL' || event.target.tagName === 'SPAN') { return; }
console.log('Performing some action only once. Triggered by click on: '+event.target.tagName);
}
上的某个位置,但不要直接单击文本或复选框。
我添加了我的答案,因为我不认为这是OP的意图。
但即使对于其他情况,您也可以使用我上面提到的类似方法。检查点击的元素名称是否为DIV,然后允许进一步的操作。我认为它更直接,更局部化(不影响事件传播),更通用(如果你选择捕获:addEventListener(...,...,true)这仍然有用)