精华 AngularJS 简单介绍
发布于 10 年前 作者 russj 10782 次浏览 最后一次编辑是 8 年前 来自 分享

首先,AngularJS 是建立在轻量 jQuery 之上的一个结构化前端 MVVM 框架。

相比较 Facebook 的 React,个人觉得 AngularJS 可能更适合企业用户,创建单页面的 CRUD 应用。例如对表格表单的处理,AngularJS 就能展现其强大快捷的一面。

另外,AngularJS 非常结构化,大而全,坏处就是规定比较严格,好处是代码更一致,而且有一套很完善的测试流程支持。但是性能经常受人诟病。企业用户可能对性能没有那么敏感,反而喜欢这种写起来条理清晰,功能强大的框架。这有点像 Java,虽然臃肿,慢,但是成熟稳定,所以企业往往选择这样的框架。不过 React 也不是一个框架,不好比较。

Template 和 Directive

相比较 jQuery 通过直接操作 DOM 来编辑页面,AngularJS 引入了模板(template)和 指令(directive)来创建 HTML 的视图 view。

指令 directive 包含两部分。一个是 HTML 模板上额外的属性 attribute,elements 和 CSS 类等;另一个部分是扩展 DOM 行为的 JavaScript 代码。

AngularJS 鼓励只使用 directive 来操作 DOM.

表达式 Expression

这个很多模板都有。就是可以在模板里进行些简单的运算使代码更紧凑。

AngularJS 的 Expression 就算遇到操作 undefined 或者 null 变量也不抛出异常,只是简单地把它们当做没有值对待。你也不能主动抛出异常。

Expression 不能有循环和条件语句。

控制器 Controller

JavaScript 代码, 用于更新 $scope 的变量,操作页面逻辑等,但是不要把业务逻辑放在这里。controller 里的 $scope 是唯一页面数据来源。不要直接修改 DOM。

数据绑定 Data Binding

AngularJS 里最好用的特性之一。可以直接把 HTML 里的 ng-model 和 Controller 里 $scope 的变量双向绑定,这样其中一个改变,另外一端就会自动更行。不过情况复杂时也得使用 $scope.apply() 来强制更新。

服务 Services

一些干活的单例对象。比如 AJAX 请求,logging,动画和解析等。也可以创建自己的服务来复用代码。一般和数据库和其他后端服务打交道都用服务。 Service 都是单例 singleton 对象。

依赖注入 Depenency Injection

依赖注入是一种设计模式。在服务器端用得比较多。AngularJS 是比较早的把依赖注入引入到前端的框架。

注入就是把一个对象引入另外一个对象来达到代码复用的目的。比如上面的服务模块就是这样注入到需要的模块。这样做的另外一个好处就是代码更加清晰。

AngularJS 通过 providers 和 injector service 来达到依赖注入的目的。Provider 就是要注入的对象,通常是一个 AngularJS 模块 module 的一部分(例如 app.factory(), value(), constant() 和 service()函数,这也是4种常用的service;还有 controller(), animation(), filter() 和 directive()),然后注册到 injector 服务。注意 provider 是单例模式,当有依赖请求,injector 服务会检查是否已经有这个 provider 在运行,有则调用这个已经存在的,没有才会在 injector 的 cache 里创建一个新实例(instance)。

AngularJS Modules

AngularJS Modules 的实现分两个阶段:配置和运行。配置就是调用 Module 的 config 方法;运行调用 run 方法。不过 run 用得不多,一般都是用 controller 来控制。

调用 angular.module() 方法就可以创建一个模块,也就是一个 Module 对象的实例。同时它还会把这个实例注册到前面提到的 injector 服务。

注意以下的区别:

//带[]。这是创建一个新的 “myModule”.如果已有这个模块,则会覆盖之前的
angular.module("myModule", []); 

//没有第二个参数[]。返回已经存在的同名模块。如果没有则会报错。
angular.module("myModule");

责任分离

之前说 AngularJS 很结构化就是讲究责任分离,这样代码才好理解,维护和测试。

结构化的代价就是有很多规则要遵守(所以很多人说 Angular 入门容易精通难):

  • 在 HTML 里使用 directive 来作为表现层的逻辑
  • 使用定制的 directive 来操作 DOM
  • 使用服务 service 来复用代码,然后再使用依赖注入添加到别的模块
  • controller 里的 $scope 是唯一页面数据来源。不要直接修改 DOM。
  • controller 只是用来操作 $scope 里的数据的,不要把业务逻辑放在这里
  • controller 不要在全局范围

将业务逻辑和界面逻辑分开。Controller 里只有页面逻辑,没有业务逻辑;业务逻辑放到后端,前端通过 service 来获取。

Life Cycle

一个页面的 Angular 代码每次导入到浏览器分三阶段:导入 bootstrap,编译 compilation 和实时运行 runtime。

1. Bootstrap

第一步,下载 JavaScript 代码到浏览器。AngularJS 初始化自己的组件和初始化你写的 ng-app 模块。当你的模块加载后,注入所有依赖模块。

2. Compilation

第二步,HTML 编译。当网页加载后,一个静态的 DOM 表也会加载到浏览器。在这个编译阶段,静态 DOM 会被 AngularJS 视图的动态 DOM 取代。

这个阶段又分两部分。先是遍历静态 DOM 和收集所有 directive,然后链接 directive 与相关的 JavaScript 代码。

因为 HTML 是不区分大小写,而 AngularJS 区分,所以编译时 HTML 的标签和属性会被规范化。例如所有以下都会被规范为 ngModel。所以不是只有 ng-model 一种写法。但是大家都习惯使用 ng-model.

  • ng-model; ng_model; ng:model
  • data-ng-model; data-ng_model; data-ng:model
  • x-ng-model; x-ng_model; x-ng:model

规范化规律:

  1. 从 element/attributes 去掉 x- 和 data-。
  2. 转换 : - _ 三种分隔符为 camelCase.
3. 实时数据绑定

最后一步实时运行阶段。就是编译后到用户刷新或者离开该页面。在这个阶段,AngularJS 实现数据的双向绑定。AngularJS 的数据绑定和传统的不太一样。传统方法是从模板引擎接收到模板和数据,然后当每次收到数据更新时修改 DOM. 而 AngularJS 只编译 DOM 一次,然后只和必要的编译好的模板链接,更有效率。

添加 AngularJS 到 HTML

尽量把 angular.js 的 script tag 添加在 HTML 文件 body 里所有标签的最后。因为 angular.js 文件比较大,加载后编译器就会开始编译相应代码,然后搜索 directive。因此最后加载 angular.js 可以使网页加载更快些,或者感觉更快一些。

不过现在很多浏览器都支持 async 和 defer 加载模式,angular.js 添加位置就灵活多了。

API

AngularJS 还有一些全局函数供调用。比如深度拷贝 copy,json 对象和字符串之间的转换等。可以查看文档来了解他们的具体信息。

Protractor

Protractor 是 AnguarJS 团队在 webDriver 基础上开发的端对端 e2e 测试工具,对很多方法进行了 AngularJS 封装. 非常好用的一个测试框架, 使测试变得更加容易。

10 回复

大概看了一下,有2点意见

  1. angularjs相对来说应该是MVVM模式(只是用了controller来表达,实际是数据驱动的)。
  2. run 用得不多??run会比controller先执行,可以做很多东东,比如打开系统就强制认证登陆。

@microlv 同意你说的 MVVM。之前看 寒冬的文章 讲 MVC 过时了,就很赞同。这里的 MVC 是一个大的概念

总而言之,对于MVC 为1979年的SmallTalk设计 界面和程序都由同一种语言编写 用户输入完全由程序编写者来处理 View是单纯用于显示

对于MVVM 为2005年的WPF设计 界面多使用标记语言,程序则使用编程语言 用户输入经过UI系统底层处理和分发,多数以事件的形式被用户程序所知 View具有独立性,能够管理部分用户输入并且自行反应(它们常常被称作控件,而非视图)

这个强制认证登陆不错

依赖注入是一种设计模式,但不在23种里面,应该是bob大叔的solid的的d

@i5ting No,D 是依赖倒置原则 DIP Dependency inversion principle

程序应该依赖抽象,而不是互相依赖。 高层模块不应该依赖底层模块,两者都应该依赖其抽象

SOLID 是指导原则

我也曾经 Java 过

公司目前的项目都往AngularJS拓展了,但表示没接触到。。

@russj 依赖注入 = DI 。。。。。。

@i5ting In computer programming, SOLID (Single responsibility, Open-closed, Liskov substitution, Interface segregation and Dependency inversion)

http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

@russj 大哥。。。 Dependency = 依赖 inversion = 倒置,也就是依赖注入,另外还有一个类似概念叫IoC

@russj 再不明白,打屁屁了,哈哈

@i5ting 这个是很多人的错误理解。 你可以说它们相似,目的类似,but Injection != Inversion on the surface, the two things may look the same but there’s a very important semantic difference between them: ownership of the abstraction. Dependency Injection Is NOT The Same As The Dependency Inversion Principle

不过 JavaScript 讲究的就是乱拳打死老师傅。快速开发才是王道。等你 refactor 好了,人家都 c 轮了

回到顶部