这是对我和 Valerii 在 MoscowJS 2013 上的演讲的一个小的补充。”JavaScript @ LiveJournal” (文字是俄语的,很抱歉)。
在LiveJournal上,我们经过了很长的一个过程,从jQuery UI的扩展到BackBone,最终转移到了AngularJS,到目前为止,一切都非常好,但是AngularJS有一些小的陷阱。
-
在页面上通过 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 已经添加并确认 。
-
在
<form>
标签上使用 ng-app这一点在这个 GitHub issue 上有更好的描述,在1.2版本之后应该会被修复。
-
过多的
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 。 -
html5Mode 会禁用所有链接
这个问题非常简单,但是依然要说明一下。如果你向你的 module 注入了 $location 并且启用了 html5Mode ,页面上的所有链接会无法正常工作,因为 Angular 给它们加了 preventDefault 操作,并且转而依赖它自己的 router 。可以这样来解决这个问题
jQuery('div:not([target])').attr('target', '_self')
当然,如果链接是页面加载完成之后再动态生成的话,这会变的复杂的多。
原文地址:Angular JS pitfalls