安装 ng-mouseover 和 ng-mouseout 会导致效率极低的 AngularJS 代码

Installing ng-mouseover and ng-mouseout cause highly inefficient AngularJS code

本文关键字:AngularJS 代码 效率 ng-mouseover ng-mouseout 安装      更新时间:2023-09-26

我意识到当我安装ng-mouseoverng-mouseout事件回调时,我的整个AngularJS变得非常慢。

很快,我意识到 2 个回调将导致其他 AngularJS 函数一次又一次地重新评估,只需移动鼠标即可。

网页代码

<html ng-app="phonecatApp">
<head>
  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.9/angular.min.js"></script>
  <script src="controllers.js"></script>
</head>
<body ng-controller="PhoneListCtrl"
  ng-mouseover="onScreen($event)"
  ng-mouseout="offScreen($event)">
  <div id="dummy"
    ng-show="isLoggedIn()">
    <ul>
      <li ng-repeat="phone in phones">
        <span>{{phone.name}}</span>
        <p>{{phone.snippet}}</p>
      </li>
    </ul>
  </div>
</body>
</html>

控制器.js

var phonecatApp = angular.module('phonecatApp', []);
phonecatApp.controller('PhoneListCtrl', function ($scope) {
  $scope.phones = [
    {'name': 'Nexus S',
     'snippet': 'Fast just got faster with Nexus S.'},
    {'name': 'Motorola XOOM™ with Wi-Fi',
     'snippet': 'The Next, Next Generation tablet.'},
    {'name': 'MOTOROLA XOOM™',
     'snippet': 'The Next, Next Generation tablet.'}
  ];
  $scope.onScreen = function (e) {
  };
  $scope.offScreen = function (e) {
  };
  $scope.isLoggedIn = function() {
      console.log("isLoggedIn : " + new Date().getTime());
      return true;
  };
});

在上面的示例中,ng-mouseoverng-mouseout只是简单地调用空函数。但是,如果我尝试将鼠标移到浏览器上,我会意识到isLoggedIn被多次触发。

我可以知道为什么AngularJS会有这样的行为吗?我怎样才能避免这种情况?

这是

非常预期的行为:

  • 鼠标悬停/鼠标退出事件在 DOM 树中冒泡(请参阅事件冒泡)。这意味着即使您将鼠标悬停在页面中的任何内容上(当然是在正文标记内),它也会冒泡并运行在正文上注册的鼠标悬停/mouseout 事件处理程序。

  • Angular 运行所有观察程序(摘要周期),以便更新视图上的任何 DOM 绑定,以反映这些事件通过 scope.$apply() 触发时对范围属性的任何更改。

  • 上一步会导致表达式 @ ng-show="isLoggedIn()" 再次计算isLoggedIn()因为 ng-show 指令也会创建一个观察程序。

相反,如果适用,请使用mouseenter/mouseleave因为这些事件不会冒泡,只会在您专注于页面并离开时运行。

<body ng-controller="PhoneListCtrl"
     ng-mouseenter="onScreen($event)"
     ng-mouseleave="offScreen($event)">

另一件事是尽量避免在角度绑定中绑定函数表达式,尝试绑定到属性。

示例:您应该在适用的情况下设置$scope.status.isLoggedIn,并在 @ ng-show="status.isLoggedIn" ng-show 中使用该标志。当然,如果您确实需要防止发生任何摘要,请创建自定义指令而不是ng-mouseenter/leave并在那里执行滑动菜单显示。也就是说,您必须手动执行此操作,而不是通过 DOM 作用域绑定为您执行 angular 的操作。