DanLevy.net

AngularJS 技巧

AngularJS 也可以很有趣!

Hero image for AngularJS 技巧

AngularJS 也可以很好玩!

适用版本:AngularJS v1.x

  1. AngularJS 开发者很快就会发现,随着应用规模增长,散落各处的 $watch 和臃肿的 $scope 支柱会让系统不堪重负。
  2. 确保你的 $scope 不被多余的 UI 状态占满,尽量限制整体层级的规模和深度。

双向数据绑定:双刃剑

单就双向绑定而言,从 Backbone 等框架转过来的开发者会觉得这简直爽翻了

问题在于:许多网站过度使用了 Angular 的设计模式。 这导致指令(directive)泛滥,$scope/rootScope 动辄产生数千个实例,并死死抓着大对象不放,让有效的垃圾回收(GC)彻底泡汤。

结局显而易见:浏览器精疲力竭!永远陷入在执行无休止且冗余的 UI/DOM 重绘重排的疯狂节奏中。

停止“过度 Angular 化”

“如果你手里只有一把锤子,那么所有问题看起来都像钉子。”

—— 古谚语

你的应用是否存在指令滥用的问题?

current-user-status-label
div(ng-if='loggedIn')
view-user-surplusage(ng-if='!editMode')
.head: contact-details(user='user')
.tool: contact-buttons(loggedIn='loggedIn')
a.edit-icon(ng-click='editMode = true')
edit-user-surplusage(ng-if='editMode')
.head: avatar-edit(user='user')
.body: edit-contact-details(user='user')
a.save-icon(ng-click='editMode = false')

让我们设计一个灵活的用户组件(user-widget),目标是:

  1. 通过 DRY(不自我重复)的 Angular 代码实现通用的组件化。
  2. 指令易于理解,且保持极小的指令尺寸/深度(留意你的 ng-repeat)。
  3. 简单的服务层(Service Layer)。
  4. 极少的实现代码——只需 HTML/视图代码。
// jade
user-widget
div(ng-if='loggedIn')
div.edit(ng-if='editMode')
h4.email-icon: input(type='email', ng-model='user.email')
h4.phone-icon: input(type='email', ng-model='user.phone')
a.save-icon(ng-click='editMode = false')
div.show(ng-if='!editMode')
h1.users-icon {{ user.name }}
h4.email-icon {{ user.email }}
h4.phone-icon {{ user.phone }}
a.edit-icon(ng-click='editMode = true')
div(ng-if='!loggedIn')
h5: i Welcome User
a.btn(href='/login') Login

解决方案

Angular 小技巧

  1. 使用单向绑定(例如:{ :: title })。
  2. 限制指令的递归嵌套。
  3. 如果必须嵌套指令,绝不要ng-repeat 内部这样做——性能开销会开始趋向于 O(n^2)^3 这种恐怖的量级 ;) I. 使用工厂模式编写原生 JS/DOM 代码来创建基础 DOM/UI 片段,例如:模态消息框、状态栏。从指令或控制器中调用这些 UI 工厂。
  4. 进阶: 理解浏览器渲染生命周期的成本和触发机制:动画、复合渲染(composite rendering)、重排(reflows)。

使用 Browserify 组织项目

这并非专门针对 Angular,但对于简单的依赖解析至关重要。

Browserify 让 JS 项目变得易于管理,且几乎没有额外的代码开销(好吧,也就几百个字符)。

直接阅读 Browserify 手册这个章节即可。

替代方案

来自 Facebook 的 ReactJS

如果你有大量细碎的可复用 UI 组件,ReactJS 可能是更好的选择:

来自 Google 的 Polymer 项目

更纯粹的 JS 方案