Javascript 单击事件触发两次,即使使用 stopPropagation
Javascript click event firing twice, even with stopPropagation
我有一组这样的物品:
<label for="Cadenza-1" class="cars">
<input type="checkbox" value="1" alt="Cadenza" id="Cadenza-1" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza</span>
</label>
大约有 13 个。我想在单击时向标签添加 class 。但是,单击事件会触发两次。现在我正在调试点击事件,然后我将添加 class:
var cars = document.getElementsByClassName('cars');
for(var c = 0;c < cars.length; c++){
cars[c].addEventListener("click", function(e){
selectVehicle(cars[c],e);
},false);
}
function selectVehicle(el,e) {
console.log(e);
e.stopPropagation();
}
console.log
触发两次。
尝试在 stopPropogation 之后添加 preventDefault:
function selectVehicle(el,e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
}
我认为最好将 console.log(e) 放在 stopPropogation & preventDefault 之后。然后您还需要实现将复选框设置为已选中的功能,因为这可以防止这种情况发生。
当 <span>
或 <img>
接收到 "click" 事件时,这会将 DOM 冒泡到 <label>
元素,并且您的将调用事件处理程序。 <label>
然后在 <input>
元素上触发 另一个 "click" 事件,并且还会冒泡到 <label>
.
您可以检查处理程序以查看 <input>
是否被点击:
function selectVehicle(el,e) {
if (e.target.tagName !== "INPUT") return;
// do stuff
}
或者,您可以只将 "click" 处理程序添加到 <input>
本身。
现在您还会注意到您的代码无法正常工作,因为您遇到了在循环内绑定事件处理程序的常见问题。问题是当事件处理程序实际 运行 时,变量 c
的值将是 cars
列表的长度。有几种方法可以解决这个问题;一种是使用 forEach()
循环而不是 for
循环:
[].forEach.call(cars, function(car) {
car.addEventListener("click", function(e){
selectVehicle(car,e);
}, false);
});
您正在将事件侦听器添加到标签,您应该将事件侦听器添加到复选框,因为标签行为复制在 for 中指定的相同输入。
请注意,如果您只单击复选框,回调会正常工作,这是因为标签上的事件是由复选框引发的。
正确的做法是只为复选框添加事件侦听器或在 setlectVehicle 回调中添加阻止默认值。
您不需要 preventDefault 或 stopPropagation,只需在输入元素上添加监听器即可。
cars[c].children[0].addEventListener("click", function(e) {
试试这个。它按预期工作。
此外,如果标签元素包含所需的 input/other 元素,则不需要将 ID 与标签一起使用
var cars = document.getElementsByClassName('cars');
for (var c = 0; c < cars.length; c++) {
cars[c].children[0].addEventListener("click", function(e) {
selectVehicle(cars[c], e);
}, false);
}
function selectVehicle(el, e) {
console.log(e);
}
<label class="cars">
<input type="checkbox" value="1" alt="Cadenza" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza</span>
</label>
<label class="cars">
<input type="checkbox" value="1" alt="Cadenza" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza 2</span>
</label>
我有一组这样的物品:
<label for="Cadenza-1" class="cars">
<input type="checkbox" value="1" alt="Cadenza" id="Cadenza-1" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza</span>
</label>
大约有 13 个。我想在单击时向标签添加 class 。但是,单击事件会触发两次。现在我正在调试点击事件,然后我将添加 class:
var cars = document.getElementsByClassName('cars');
for(var c = 0;c < cars.length; c++){
cars[c].addEventListener("click", function(e){
selectVehicle(cars[c],e);
},false);
}
function selectVehicle(el,e) {
console.log(e);
e.stopPropagation();
}
console.log
触发两次。
尝试在 stopPropogation 之后添加 preventDefault:
function selectVehicle(el,e) {
console.log(e);
e.stopPropagation();
e.preventDefault();
}
我认为最好将 console.log(e) 放在 stopPropogation & preventDefault 之后。然后您还需要实现将复选框设置为已选中的功能,因为这可以防止这种情况发生。
当 <span>
或 <img>
接收到 "click" 事件时,这会将 DOM 冒泡到 <label>
元素,并且您的将调用事件处理程序。 <label>
然后在 <input>
元素上触发 另一个 "click" 事件,并且还会冒泡到 <label>
.
您可以检查处理程序以查看 <input>
是否被点击:
function selectVehicle(el,e) {
if (e.target.tagName !== "INPUT") return;
// do stuff
}
或者,您可以只将 "click" 处理程序添加到 <input>
本身。
现在您还会注意到您的代码无法正常工作,因为您遇到了在循环内绑定事件处理程序的常见问题。问题是当事件处理程序实际 运行 时,变量 c
的值将是 cars
列表的长度。有几种方法可以解决这个问题;一种是使用 forEach()
循环而不是 for
循环:
[].forEach.call(cars, function(car) {
car.addEventListener("click", function(e){
selectVehicle(car,e);
}, false);
});
您正在将事件侦听器添加到标签,您应该将事件侦听器添加到复选框,因为标签行为复制在 for 中指定的相同输入。
请注意,如果您只单击复选框,回调会正常工作,这是因为标签上的事件是由复选框引发的。
正确的做法是只为复选框添加事件侦听器或在 setlectVehicle 回调中添加阻止默认值。
您不需要 preventDefault 或 stopPropagation,只需在输入元素上添加监听器即可。
cars[c].children[0].addEventListener("click", function(e) {
试试这个。它按预期工作。
此外,如果标签元素包含所需的 input/other 元素,则不需要将 ID 与标签一起使用
var cars = document.getElementsByClassName('cars');
for (var c = 0; c < cars.length; c++) {
cars[c].children[0].addEventListener("click", function(e) {
selectVehicle(cars[c], e);
}, false);
}
function selectVehicle(el, e) {
console.log(e);
}
<label class="cars">
<input type="checkbox" value="1" alt="Cadenza" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza</span>
</label>
<label class="cars">
<input type="checkbox" value="1" alt="Cadenza" name="vehicles[]">
<img src="img/bill_murray_173x173.jpg">
<span>Cadenza 2</span>
</label>