如何在单击标签内的文本时使函数不触发两次。
如果我使用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>
答案 0 :(得分:2)
据我了解,您希望点击.parent
元素以触发点击处理程序,但您不希望针对与.parent
中的复选框或其标签相关的点击触发该处理程序。 / p>
两种方法:
为调用label
的{{1}}添加处理程序,或
在事件处理程序中检查事件是否通过stopPropagation
方法1:
label
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;
}
这里的方法2:
<div class="parent">
<label for="option1">
<span>Select me</span>
<input id="option1" type="checkbox">
</label>
</div>
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;
}
答案 1 :(得分:0)
这是标准的(不幸的)浏览器行为。
属性for
将<label>
分配给<input>
,因此,当单击<label>
元素时,浏览器将在您真正点击后立即模拟对<input>
元素的点击。
这允许文本<input>
的焦点,单选<input>
的切换或复选框<input
>的切换。
但是对于不幸的部分,这也会导致两个元素都发送 click 事件。如果您正在监听父元素的点击,这意味着您将两次收到一次“人机交互”。一次来自<input>
,一次来自“被点击的元素”。
对于那些想知道<input>
could be inside <label>
元素的人来说,样式的可能性会降低,但是您可以在复选框和文本之间单击。
您将<span>
和<input>
放在<label>
中实际上创建了一个不错的测试用例。
尝试从左到右点击;
在文本上,您将收到SPAN + INPUT事件,
在文本和复选框之间,您将获得LABEL + INPUT事件,
在复选框上仅直接输入事件,
然后再继续,只有DIV事件。
(因为DIV是一个块元素,并且一直向右延伸)
一种解决方案是仅监听<input>
个元素事件,但是您将不会捕获<div>
次点击,也无法将<div>
放在<label>
内。
最简单的方法是忽略<label>
上的点击以及<label>
中除<input>
之外的所有可点击元素。在这种情况下,<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);
}
<div class="wrapper">
<label for="option1">
<span>Select me</span>
<input id="option1" type="checkbox">
</label>
</div>
*)在我的示例中,我将类名称 parent 更改为 wrapper ,并将包含div元素的变量名称 label 更改为 elWrapper , 因为父级和标签是关键字,将它们用于其他方式可能会造成混淆。
@ T.J。的解决方案导致<label>
中的事件及其中的所有事件在以后被忽略。
要触发事件,您需要点击<div>
上的某个位置,而不是直接在文本或复选框上单击。
我添加了我的答案,因为我不认为这是OP的意图。
但是,即使是这种情况,您也可以使用上面提供的类似方法。检查单击的元素名称是否为DIV,然后允许采取进一步措施。我认为它更直接,更本地化(不影响事件传播),更通用(如果您选择捕获:addEventListener(...,...,true)仍然可以使用)