【译】AngularJS的一些陷阱

这是对我和 Valerii 在 MoscowJS 2013 上的演讲的一个小的补充。”JavaScript @ LiveJournal” (文字是俄语的,很抱歉)。

在LiveJournal上,我们经过了很长的一个过程,从jQuery UI的扩展到BackBone,最终转移到了AngularJS,到目前为止,一切都非常好,但是AngularJS有一些小的陷阱。

  1. 在页面上通过 pushState 来使用 $location

    如果你想要使用 history.pushState 改变URL参数,来向旧的页面注入一些 Angular 代码,我想你会遇到一些很糟糕的情况。在我们的案例中,旧的代码修改了 location.search 之后,Angular 会尝试通知所有的 Controller 这个变动,但是因为这个变动来自于非Angular代码,因此 digest 就会进入死循环。我想这应该是老版本代码中的一个bug,但是我们不想触发它,因此,我们需要找到某种方法来屏蔽掉它。问题在于,我们没有手动向任何一个 module 注入 $location。在通过一些追踪之后,我们发现,ng-include 依赖于 $anchorScroll,而这个方法在被调用时,会依赖 $location。在做了一些仔细的测试,以了解为什么 ng-include 需要这些之后,我们决定使用这样一个 hack :

    angular.module('ourModule', []).value('$anchorScroll', null);
    

    页面上没有$location,意味着没有events也就意味着没有死循环。

    测试示例: http://jsbin.com/IxAGEzI/1

    更新:issue 已经添加并确认 。

  2. 在 <form> 标签上使用 ng-app

    这一点在这个 GitHub issue 上有更好的描述,在1.2版本之后应该会被修复。

  3. 过多的 scope.$apply()

    $apply 是一个代价很大的操作。我们有一个叫做 lj-popup 的 directive,它的作用类似于 lj-popup="popupState" 同时监视 document 文档上的点击。如果点击发生在 ng-app 作用的节点以外(或者按了 ESC 键),就将 popupState 设置为 false 。因此我们使用 $parse setter(assgin)来设置变量和 $apply 。如果页面上有许多 directive 实体,你会遇到一个问题。解决方法是使用常规的检测并且避免使用 $apply ,除非它是必要的。在 lj-popup 的例子中,我们检查 popup 是否是打开的,并且只有在打开的情况下触发 $apply 。

  4. html5Mode 会禁用所有链接

    这个问题非常简单,但是依然要说明一下。如果你向你的 module 注入了 $location 并且启用了 html5Mode ,页面上的所有链接会无法正常工作,因为 Angular 给它们加了 preventDefault 操作,并且转而依赖它自己的 router 。可以这样来解决这个问题

    jQuery('div:not([target])').attr('target', '_self')
    

    当然,如果链接是页面加载完成之后再动态生成的话,这会变的复杂的多。

原文地址:Angular JS pitfalls