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

时间:2015-01-19 02:41:30

标签: javascript html angularjs

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

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

HTML代码

<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>

controllers.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有这样的行为吗?我怎么能避免这样的?

1 个答案:

答案 0 :(得分:6)

这是非常期待的行为:

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

  • Angular运行所有观察者(digest cycle),以便更新视图上的任何DOM绑定,以反映作为events gets triggered {{3}}通过scope.$apply()的范围属性的任何更改。

  • 上一步导致isLoggedIn()表达式@ ng-show="isLoggedIn()"再次被评估,因为ng-show指令也会创建一个观察者。

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

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

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

示例:您应该在适用的地方设置$scope.status.isLoggedIn,并在ng-show @ ng-show="status.isLoggedIn"中使用该标记。当然,如果您确实需要阻止任何摘要发生,请创建自定义指令而不是ng-mouseenter/leave并在那里执行滑动菜单显示。那就是你必须手动完成,而不是通过DOM范围绑定为你做角度。