Angular中ng-click绑定div函数 单次点击触发执行两次问题
问题描述
我在Web应用中使用Angular框架,在div标签上通过ng-click绑定函数来修改复选框的值,但点击该div时绑定的函数会执行两次。
HTML代码
<div class="switch" ng-click="f_changeSwitch(a_Order.isInSaloon)"> <label> <span>{{lang==1 ? 'سالن' : 'Saloon'}}</span> <input ng-model="a_Order.isInSaloon" type="checkbox"> <span class="lever lever_c"></span> {{lang==1 ? 'بیرون بر' : 'Take Away'}} </label> </div>
JavaScript代码
$scope.f_changeSwitch = function (saloon) { console.log("counter", counter); console.log("saloon", saloon); console.log("$scope.a_Order.isInSaloon", $scope.a_Order.isInSaloon); if ($scope.a_Order.isInSaloon == true) { $scope.a_Order.isInSaloon = false; } else { $scope.a_Order.isInSaloon = true; } if ($scope.a_Order.isInSaloon == false) { $scope.packAge_Cost = {}; $scope.packAge_Cost.a_tProductId_packageCost = $scope.a_tProductId_packageCost; $scope.packAge_Cost.t = $scope.a_prName; $scope.packAge_Cost.a_prName_EN = $scope.a_prName_EN; $scope.packAge_Cost.total = $scope.packAgeCostInNumber; $scope.ordered_item.push($scope.packAge_Cost) $scope.a_invTotal = $scope.a_invTotal + $scope.packAgeCost $scope.a_invTotalString = f_Cash2String($scope.a_invTotal); console.log("$scope.packAgeCost1234", $scope.packAgeCost); } else { $scope.a_invTotal = $scope.a_invTotal - $scope.packAgeCost; $scope.a_invTotalString = f_Cash2String($scope.a_invTotal); console.log("is in saloon is true now") } counter++ }
运行现象
单次点击后计数变为2,控制台日志显示绑定的函数被触发两次。
触发原因
两次执行的根源是原生label默认行为+事件冒泡+ng-model双向绑定的逻辑叠加:
- 外层带
switch类的div本身绑定了ng-click,点击该区域时首先会触发f_changeSwitch执行一次。 - div内部嵌套了
<label>标签,原生label的默认逻辑是:点击label内任意区域,都会触发其关联的表单元素(也就是绑定了同一个a_Order.isInSaloon的checkbox)的点击事件。 f_changeSwitch内部手动修改了$scope.a_Order.isInSaloon的值,同时checkbox的ng-model已经绑定了该值,事件冒泡过程中checkbox的原生点击会再次翻转状态,最终相当于事件被两层触发,导致函数执行两次。
另外现有代码存在冗余:f_changeSwitch里手动翻转isInSaloon的逻辑完全多余,checkbox本身绑定ng-model后,用户点击即可自动更新对应的值。
解决方案
按改动量从小到大选即可:
- 最小改动:阻止事件冒泡
给内层的checkbox加上ng-click="$event.stopPropagation()",阻断label到外层div的事件冒泡,避免双层触发。<input ng-model="a_Order.isInSaloon" type="checkbox" ng-click="$event.stopPropagation()"> - 优化方案:移除外层多余的逻辑绑定
既然已经用checkbox绑定了ng-model,完全不需要在div上绑ng-click来手动修改值,直接把状态变更的副作用逻辑(比如修改总价、添加打包费的部分)挪到ng-change指令上即可,ng-change会在isInSaloon的值真正变更时才触发,不会出现重复执行的问题:
同时把JS里手动翻转<div class="switch"> <label> <span>{{lang==1 ? 'سالن' : 'Saloon'}}</span> <input ng-model="a_Order.isInSaloon" type="checkbox" ng-change="f_changeSwitch()"> <span class="lever lever_c"></span> {{lang==1 ? 'بیرون بر' : 'Take Away'}} </label> </div>isInSaloon的代码删掉,避免重复改值:$scope.f_changeSwitch = function () { // 此处删除原有手动翻转isInSaloon的if判断代码,该值已由ng-model自动更新 if ($scope.a_Order.isInSaloon == false) { $scope.packAge_Cost = {}; $scope.packAge_Cost.a_tProductId_packageCost = $scope.a_tProductId_packageCost; $scope.packAge_Cost.t = $scope.a_prName; $scope.packAge_Cost.a_prName_EN = $scope.a_prName_EN; $scope.packAge_Cost.total = $scope.packAgeCostInNumber; $scope.ordered_item.push($scope.packAge_Cost) $scope.a_invTotal = $scope.a_invTotal + $scope.packAgeCost $scope.a_invTotalString = f_Cash2String($scope.a_invTotal); } else { $scope.a_invTotal = $scope.a_invTotal - $scope.packAgeCost; $scope.a_invTotalString = f_Cash2String($scope.a_invTotal); } } - 兜底方案:添加防抖判断
如果因业务限制无法修改现有绑定逻辑,就在函数开头加时间戳判断,短时间内的重复触发直接拦截:let lastClickTime = 0; $scope.f_changeSwitch = function (saloon) { const now = Date.now(); // 200毫秒内的重复触发直接返回 if (now - lastClickTime < 200) return; lastClickTime = now; // 原有业务逻辑正常执行 }
内容的提问来源于stack exchange,提问作者omid mohamadi
相关产品推荐
相关产品推荐

