我无法弄清楚在这个demo中,为什么单击标签会触发两次滑动动画,而单击复选框会触发一次滑动动画。有人可以解释一下吗?谢谢!
我在这里附上代码。
<div ng-app="labelApp" ng-controller="labelCtrl">
<label ng-click="toggle()">
<input type="checkbox">Click to toggle slide</label>
<div id="myDiv">
Clicking check box triggers sliding animation once.
<br>
Clicking label triggers sliding animation twice.
</div>
</div>
angular.module("labelApp", [])
.controller("labelCtrl", function($scope) {
$scope.toggle = function() {
$("#myDiv").slideToggle();
}
});
答案 0 :(得分:4)
当您点击label
时,该事件将向下延伸到input
,这将导致复选框被选中,然后它将再次冒泡回到label
。因此,label
上的处理程序会被触发两次。快速解决方法是将处理程序放在输入上:
<label>
<input ng-click="toggle()" type="checkbox">Click to toggle slide
</label>
但可能更合适的是使用ng-change
:
<input ng-change="toggle()" ng-model="isChecked" type="checkbox">Click to toggle slide
答案 1 :(得分:0)
当触发子元素时,事件会冒泡并且所有父元素也会被触发,除非传播停止。
带有封闭输入的标签具有触发它们所附加输入的点击事件以及它们自身的属性,因此单击标签会触发事件及其附加输入。在这种情况下,附加的输入是它的子输入,所以当它被触发时,它会回弹到作为标签的父项。所以实际上标签是第二次触发它。
您可以在此处查看分离的标签如何触发输入的点击事件:https://jsfiddle.net/yosefh/14qtas7q/以及在此处解决此问题的方法https://stackoverflow.com/a/30810281/6419701
要解决您的问题,您可以通过向复选框添加ng-click="$event.stopPropagation()"
来停止对输入的传播。但如果你这样做,那么事件只会由标签而不是复选框触发。
顺便说一下,如果将label元素更改为div元素,则不会出现此问题。
虽然在语义上,最好将标签用于标签而不是将其变成div。
所以你可以简单地将ng-click移动到我在这里完成的复选框
<div ng-app="labelApp" ng-controller="labelCtrl">
<label>
<input type="checkbox" ng-click="toggle()">Click to toggle slide
</label>
<div id="myDiv">
Clicking check box triggers sliding animation once.
<br>
Clicking label triggers sliding animation twice.
</div>
</div>
https://jsfiddle.net/yosefh/9uf9vpyk/
您可以在此处看到类似的问题:Angular.js ng-click events on labels are firing twice
如果您一般遇到事件传播问题,可以看到这篇文章 https://stackoverflow.com/a/15193650/6419701