AngularJS菜单点击事件Chrome正常但Firefox偶发失效问题咨询
可能根因
事件绑定的时序逻辑缺陷
你将点击事件的绑定逻辑放在了report-loaded事件的回调中,且仅在scope.reportViewData.reportCommand.fullReport为false时才执行绑定。Firefox的AngularJS生命周期、资源加载时序和Chrome存在差异,绝大多数场景下report-loaded触发时fullReport已经被赋值为true,直接跳过了事件绑定的逻辑,仅当时序抖动刚好让report-loaded触发时fullReport还未被赋值为true时,事件才能绑定成功,这也符合你提到的10次尝试仅1次正常的现象。事件绑定重复/丢失问题
如果report-loaded事件被多次触发,你没有做去重绑定的处理,多次绑定可能导致Firefox的事件队列出现异常,吞噬了点击事件;另外你当前的绑定逻辑依赖异步事件的触发顺序,Firefox的异步任务调度优先级和Chrome不同,偶尔会出现事件绑定晚于用户交互的情况。DOM渲染时序不兼容
你在fullReport为true的分支中使用了无延迟的$timeout执行初始化逻辑,Firefox的DOM渲染优先级低于Chrome,无延迟$timeout执行时ng-repeat渲染的菜单DOM还未完全生成,会导致后续的事件交互异常。
修复方案
- 把事件绑定逻辑从
report-loaded回调中挪到link函数外层,无论fullReport取值如何都完成事件绑定,避免时序依赖:
link: function(scope, element, attrs){ // 先做事件绑定,防止重复绑定 element.off('click', scope.handleClickEvent).on('click', scope.handleClickEvent); $rootScope.$on('report-loaded', function(event, args){ // 原有其他逻辑保留 scope.horizontal = scope.$eval(attrs.horizontal); if(scope.reportViewData.reportCommand.fullReport) { // 给$timeout加50ms延迟,等待ng-repeat渲染完成 $timeout(function(){ angular.element("li.tabMenu-item").each(function () { var curObj = angular.element(this); var event = { target: curObj, preventDefault: function () {} } scope.handleClickEvent(event); }); angular.element('.floatmenu').floatmenu(); },50); } }); }
- 优化
handleClickEvent的事件对象兼容逻辑,移除对非标准属性srcElement的依赖:
$scope.handleClickEvent = function (event) { angular.element(".tabMenu").find(".submenu").hide(); var tarEle = event.target; // 兼容Firefox下点击到文本节点的场景 if(tarEle.nodeType === 3) tarEle = tarEle.parentNode; var parentEle = angular.element(tarEle).closest("li.tabMenu-item"); if (parentEle.length && !parentEle.hasClass("nodata") && !parentEle.hasClass("sel") && parentEle.attr("id") !== undefined) { parentEle.find(".submenu").show(); angular.element("#reportsMenu").find(".sel").removeClass("sel"); parentEle.addClass("sel"); var reportObj = $scope.reportDetail; // 原有业务逻辑保留 } else { event.preventDefault(); } }
内容的提问来源于stack exchange,提问作者Code is Cheap Show me The Talk
相关产品推荐
相关产品推荐

