Skip to Content
AngularJS1 Angular 语言规则

1 Angular 语言规则

使用 Closure 的 goog.require 和 goog.provide 管理依赖

为您的项目选择一个命名空间,并使用 goog.provide 和 goog.require。

goog.provide('hello.about.AboutCtrl'); goog.provide('hello.versions.Versions');

为什么? Google BUILD 规则与 Closure 的 provide/require 能很好地集成。

模块(Module)

您的主应用模块应该位于客户端根目录中。模块只能在其定义所在的位置被修改,不应在其他地方修改。

模块可以与其组件定义在同一文件中(这适用于只包含一个服务的模块),也可以在单独的文件中将各部分组合在一起。

为什么? 模块对于任何想将其作为可重用组件引入的人来说应该是一致的。如果一个模块的含义取决于包含了哪些文件,那它就不是一致的。

模块应使用 Angular Module 的 “name” 属性引用其他模块

例如:

// 文件 submodulea.js: goog.provide('my.submoduleA'); my.submoduleA = angular.module('my.submoduleA', []); // ... // 文件 app.js goog.require('my.submoduleA'); Yes: my.application.module = angular.module('hello', [my.submoduleA.name]); No: my.application.module = angular.module('hello', ['my.submoduleA']);

为什么? 使用 my.submoduleA 的属性可以避免 Closure 预提交检查报错(提示文件被引入但从未使用)。使用 .name 属性可以避免重复字符串。

使用通用的 externs 文件

这能最大程度地让 JS 编译器在存在 Angular 外部提供的类型时执行类型安全检查,并且意味着您不必担心 Angular 变量被以令人困惑的方式混淆。

Google 外部读者请注意:当前的 externs 文件位于 Google 内部目录中,但可以在 GitHub 上找到一个示例 这里 

JSCompiler 标志

提醒:根据 JS 风格指南,面向用户的代码必须进行编译。

推荐:使用 JSCompiler(默认与 js_binary 配合使用的 Closure 编译器)并使用 //javascript/angular/build_defs/build_defs 中的 ANGULAR_COMPILER_FLAGS_FULL 作为基础标志。

注意——如果您对方法使用了 @export,则需要添加编译器标志:

"--generate_exports",

如果您对属性使用了 @export,则需要添加以下标志:

"--generate_exports", "--remove_unused_prototype_props_in_externs=false", "--export_local_property_definitions",

控制器(Controller)和作用域(Scope)

控制器是类。方法应该定义在 MyCtrl.prototype 上。

Google 的 Angular 应用应使用 ‘controller as’ 风格将控制器导出到作用域上。这在 Angular 1.2 中已完全实现,在 Angular 1.2 之前的版本中也可以模拟实现。

在 Angular 1.2 之前,写法如下:

/** * Home 控制器。 * * @param {!angular.Scope} $scope * @constructor * @ngInject * @export */ hello.mainpage.HomeCtrl = function($scope) { /** @export */ $scope.homeCtrl = this; // 这是在 Angular 1.2 controller-as 之前的过渡方案 /** * @type {string} * @export */ this.myColor = 'blue'; }; /** * @param {number} a * @param {number} b * @export */ hello.mainpage.HomeCtrl.prototype.add = function(a, b) { return a + b; };

对应的模板:

<div ng-controller="HomeCtrl"> <span ng-style="homeCtrl.myColor">I'm in a color!</span> {{homeCtrl.add(5, 6)}} </div>

在 Angular 1.2 之后,写法如下:

/** * Home 控制器。 * * @constructor * @ngInject * @export */ hello.mainpage.HomeCtrl = function() { /** * @type {string} * @export */ this.myColor = 'blue'; }; /** * @param {number} a * @param {number} b * @export */ hello.mainpage.HomeCtrl.prototype.add = function(a, b) { return a + b; };

如果您使用属性重命名进行编译,请使用 @export 注解来暴露属性和方法。同时也要记得 @export 构造函数。

在模板中:

<div ng-controller="HomeCtrl as homeCtrl"> <span ng-style="homeCtrl.myColor">I'm in a color!</span> {{homeCtrl.add(5, 6)}} </div>

为什么? 将方法和属性直接放在控制器上,而不是构建一个作用域对象,更符合 Google Closure 的类风格。此外,使用 ‘controller as’ 可以在多个控制器作用于同一元素时,清楚地知道您正在访问哪个控制器。由于绑定中始终有一个 ’.’,您不必担心原型继承遮蔽基本类型的问题。

指令(Directive)

所有 DOM 操作都应在指令内完成。指令应保持小巧并使用组合模式。定义指令的文件应通过 goog.provide 提供一个返回指令定义对象(Directive Definition Object)的静态函数。

goog.provide('hello.pane.paneDirective'); /** * 描述和用法 * @return {angular.Directive} 指令定义对象。 */ hello.pane.paneDirective = function() { // ... };

例外:对于与视图其余部分断开的 DOM 元素(如对话框或键盘快捷键),可以在服务(Service)中进行 DOM 操作。

服务(Service)

通过 module.service 在模块上注册的服务是类。除非您需要在创建类的新实例之外进行额外的初始化,否则请使用 module.service 而不是 module.providermodule.factory

/** * @param {!angular.$http} $http Angular 的 http 服务。 * @constructor */ hello.request.Request = function($http) { /** @type {!angular.$http} */ this.http_ = $http; }; hello.request.Request.prototype.get = function() {/*...*/};

在模块中:

module.service('request', hello.request.Request);
Last updated on