AngularJS:何时应该使用Directive、Controller、Service?

(这篇文章你们一定要看,尤其初学的人,好吗亲?)

大漠穷秋 译

AngularJS是一款非常强大的前端MVC框架。同时,它也引入了相当多的概念,这些概念我们可能不是太熟悉。(译者注:老外真谦虚,我大天朝的码农对这些概念那是相当熟悉啊!)这些概念有:

  • Directive(指令)
  • Controller(控制器)
  • Service (服务)

下面我们逐个来看这些概念,研究一下为什么它们会像当初设计的那样强大,同时研究一下为什么我们要以那样的方式去使用它们。我们从Service开始。

SERVICES(服务)

如果你已经使用过AngularJS,你可能已经遇到过Service这个概念了,简而言之,Service就是【单例对象】在AngluarJS 中的一个别名。这些小东西(指单例对象)会被经常传来传去,保证你每次访问到的都是同一个实例,这一点和工厂模式不同。基于这种思想,单例对象让我们可以 实现一些相当酷的功能,它可以让很多controller和directive访问内部的数值。在#angularjs 频道(译者注:指的是原作者自己的博客频道)里面这也是非常常见的问题之一,那就是在应用中的不同代码块之间如何共享数据?我们来看这个问题。

我们首先来创建一个module(模块),本文中的所有代码都会用到这个module。

var module = angular.module( "my.new.module", [] );

下一步,我们来创建一个新的service(服务)。假设我们上面的这个module是用来管理图书的。所以,这里我们来创建一个Book service,然后把一个JSON对象数组添加到这个serice中,这些对象代表很多book数据。

 module.service( 'Book', [ '$rootScope', function( $rootScope ) {
var service = {
books: [
{ title: "Magician", author: "Raymond E. Feist" },
{ title: "The Hobbit", author: "J.R.R Tolkien" }
], addBook: function ( book ) {
service.books.push( book );
$rootScope.$broadcast( 'books.update' );
}
}
return service;
}]);

这是一个非常简单的service(有时候这样就够你用了)。我们这里正在做的事情就是在管理一个book 数组,同时还带有一个addBook方法,在有需要的时候可以添加更多书籍。addBook方法还会在application上广播一个事件,告诉所有正 在使用我们的service的人,数组已经被更新了,从而让它们自己也做一些刷新操作。现在,我们要做的就是把这个service传递给各种 controller、directive、filter,或者其它任何需要它的东西---然后它们就可以访问service中的这些方法和属性了。好, 我们来动手。

 var ctrl = [ '$scope', 'Book', function( scope, Book ) {
scope.$on( 'books.update', function( event ) {
scope.books = Book.books;
scope.$apply();//注意,原文这里少了这一行
});
scope.books = Book.books;
}]; module.controller( "books.list", ctrl );

同样非常简单。我们上面所做的就是为我们的module创建了一个新的controller。在创建的时候把$scope provdier和我们自己的Book service传递给了它。能明白我们在干嘛吗?我们把前面创建的Book service中的books数组赋给了controller内部的局部scope对象。很酷,对吧?

好,这里的核心问题是什么呢?我们节省了一些时间,并且在controller上创建了一个数组。对---我们确实这样做了。这样做确实也为我们节 约了一点时间---但是如果我们要在其它地方处理这些书籍信息应该怎么办呢?通过scope来维护数据是非常粗暴的一种方式。由于其它 controller、directive、model的影响,scope很容易就会崩溃或者变脏。它很快就会变成一团乱麻。通过一种集中的途径(在这里 就是service)来管理所有书籍数据,然后通过某种方式来请求修改它,这样不仅仅会更加清晰---同时当应用的体积不断增大的时候也更加容易管理。最 后,它还可以让你的代码保持模块化(这也是Angular很擅长的一件事情)。一旦你在其它项目中需要用到这个service,你没有必要在scope、 controller、filter等等东西里面到处去查找相关的代码,因为所有东西都在service里面!

好。那么我们什么时候应该使用service呢?答案是:无论何时,当我们需要在不同的域中共享数据的时候。另外,多亏了Angular的依赖注入系统,实现这一点是很容易并且很清晰的。

CONTROLLERS(控制器)

我们再来看控制器!除非你曾经使用过前端MVC,否则从服务端MVC的思维模式转向客户端MVC的思维模式就如同一次脑筋急转弯。为什么会这样呢? 这是因为,虽然在前端开发中controller实现了非常类似的功能,但是它同时还会实现一些与服务端controller非常不同的功能。在 Angular中,controller自身并不会处理"request",除非它是用来处理路由(route)的(很多人把这种方式叫做创建route controller---路由控制器),更明确地说,尤其是你的应用里面那些作为界面的一部分的controller,它们只会管理非常小的一段代码。

controller应该纯粹地用来把service、依赖关系、以及其它对象串联到一起,然后通过scope把它们关联到view上。如果在你的 视图里面需要处理复杂的业务逻辑,那么把它们放到controller里面也是一个非常不错的选择。回到我们前面的这个books例子,我实际上并没有什 么东西需要添加到controller里面。

但是Kirk(译者注:指本文原作者),如果我要add一本书籍应该怎么办呢?我应该在controller上面新增一个方法来处理这件事情吗? 不,原因在下面解释。因为它是DOM交互/操作的一部分。所以请把它放到directive(指令)里面。怎么做呢?很高兴你能问出这个问题。

DIRECTIVES(指令)

到目前为止,在我们所编写的大量AngularJS应用中,应用中最主要的复杂部分都在directive(指令)中。有一个强大的工具可以用来操 作和修改DOM,它也是我们这里需要讨论的内容。我们来提供一个按钮,用户通过它可以向service里面添加一本图书,以这一功能来结束此文。

一个常见的反模式(按照本人愚见)是在controller里面添加DOM交互代码。Angular对directive的定义是一段代码片段,你 可以用它来操作DOM,但是我觉得directive也是进行用户交互的很好选择。我们来扩展前面的例子,为用户提供一个按钮,通过这个按钮可以向 service里面添加一本书籍。

module.directive( "addBookButton", [ 'Book', function( Book ) {
return {
restrict: "A",
link: function( scope, element, attrs ) {
element.bind( "click", function() {
Book.addBook( { title: "Star Wars", author: "George Lucas" } );
});
}
}
}]);

很简单的东西。我们创建了一个指令,它的核心目的是简单地向books列表中添加一本书籍,books已经注册在了我们的Book服务中。我们来把这个指令应用到我们的视图中。

<button add-book-button>Add book</button>

如你所见,我们仅仅把指令当作一个元素属性来使用。每次点击这个按钮的时候,它都会把《Star Wars》(《星球大战》)这本书添加到我们的Book service中去。简单、轻松、模块化---并且易复用。好了,我们为什么不直接在控制器上面添加一个addBook之类的方法呢,比如说就像下面这 样:

 $scope.addBook = function() {
Book.addBook( { title: "Star Wars", author: "George Lucas" } );
};

这样我们也能获得同样的结果,对吧?是的,确实如此---但是这样做会带来一个重大的问题。一旦我需要在其它地方添加书籍,我必须拷贝这份代码(非 常un-DRY!)(译者注:DRY---Dont Repeat Yourself,貌似是Ruby所倡导的一个重要的编码原则。),或者进行重构(重构本身并不是什么不好的的事情)。通过直接构建一个指令的方式,我们 以后就没有必要担心这种事情了---同时下次再需要实现相同功能的时候完全不需要花任何时间。通过构建指令的方式来进行DOM交互和修改,随着业务需求的 不断介入,我们就可以立即腾出手来处理复杂性不断增加的应用了。这是相当不错的一件事情,因为它保证了我们可以更少地和自己的实现打架,并且可以一直编写 DRYer code。

Angular的模块依赖哲学无疑让它成为了一款非同凡响的框架。它让我们能够以这样一种方式来编写我们的前端代码:我们不会干翻自己,也不会干翻框架---这可能是它最强大的力量。

希望我已经充分说明了你应该在何时何地使用这几个Angular概念,从而能够更好地编写你自己的代码。

原文链接:

http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/


其它相关内容:

1、《AngularJS》一书已经由电子工业出版社出版

http://damoqiongqiu.iteye.com/blog/1965167

2、《AngularJS》5个实例详解Directive(指令)机制

http://damoqiongqiu.iteye.com/blog/1917971

3、AngularJS表单基础

http://damoqiongqiu.iteye.com/blog/1920191

4、AngularJS Form 进阶:远程校验和自定义输入项

http://damoqiongqiu.iteye.com/blog/1920993

5、AngularJS:在Windows上安装Yeoman

http://damoqiongqiu.iteye.com/blog/1885371

6、对比Angular/jQueryUI/Extjs:没有一个框架是万能的

http://damoqiongqiu.iteye.com/blog/1922004

7、使用JsTestDriver实现JavaScript单元测试

http://damoqiongqiu.iteye.com/blog/1924415

8、JavaScript单元测试系列二:将Jasmine集成到JsTestDriver

http://damoqiongqiu.iteye.com/blog/1925974

AngularJS:何时应该使用Directive、Controller、Service?的更多相关文章

  1. AngularJS入门心得1——directive和controller如何通信

    粗略地翻了一遍<JavaScript DOM编程艺术>,就以为可以接过AngularJS的一招半式,一个星期过去了,我发现自己还是Too Young,Too Simple!(刚打照面的时候 ...

  2. Directive Controller And Link Timing In AngularJS

    I've talked about the timing of directives in AngularJS a few times before. But, it's a rather compl ...

  3. AngularJs学习笔记--Understanding the Controller Component

    原版地址:http://docs.angularjs.org/guide/dev_guide.mvc.understanding_model 在angular中,controller是一个javasc ...

  4. angularjs中provider,factory,service的区别和用法

    angularjs中provider,factory,service的区别和用法 都能提供service,但是又有差别 service 第一次被注入时实例化,只实例化一次,整个应用的生命周期中是个单例 ...

  5. angularjs可交互的directive

    angularjs可交互的directive http://jsfiddle.net/revolunet/s4gm6/ directive开发上手练手,以注释的方式说明 html <body n ...

  6. [AngularJS] 使用AngularAMD动态加载Service

    [AngularJS] 使用AngularAMD动态加载Service 前言 「使用AngularAMD动态加载Controller」:这篇文章里介绍如何使用AngularAMD来动态加载Contro ...

  7. AngularJS进阶(三十六)AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记)

    AngularJS项目开发技巧之利用Service&Promise&Resolve解决图片预加载问题(后记) 前言 在"AngularJS项目开发技巧之图片预加载" ...

  8. AngularJS系统学习之Directive(指令)

    本文转自https://www.w3ctech.com/topic/1612 原文作者: Nicolas Bevacqua 原文:AngularJS’ Internals In Depth, Part ...

  9. 使用spring注解@Controller @Service @Repository简化配置

    前言:在web项目中引入spring框架中的配置文件,我们给每一个java bean进行相关配置可以非常安全,便捷的管理我们的bean.那么,问题来了,如果一个项目中所涉及到的java bean十分庞 ...

  10. SpringMVC常用注解@Controller,@Service,@repository,@Component

    SpringMVC常用注解@Controller,@Service,@repository,@Component controller层使用@controller注解 @Controller 用于标记 ...

随机推荐

  1. 1.Maven+SpringMVC+Eclipse软件安装配置,Maven报插件错误,Eclipse总是卡死的解决办法,导入一个maven工程后 一直显示importing maven project

     使用Maven+SpringMVC+Eclipse软件安装配置过程中的问题: 1.Eclipse总是卡死的解决办法: 一:内存不足所以会卡死,配置一下eclipse.ini修改这几个值就好了-X ...

  2. 套接字工厂——ServerSocketFactory

    接收器Acceptor在接收连接的过程中,根据不同的使用场合可能需要不同的安全级别,例如在支付相关的交易就必须对信息加密后再发送,这其中还涉及到密钥协商的过程,而在另外一些普通场合则无需对报文加密.反 ...

  3. SDK目录结构

    android sdk里的各目录作用 AVD Manager.exe:虚拟机管理工具,用于建立和管理虚拟机. SDK Manager.exe:sdk管理工具,用于管理.下载sdk.sdk工具,能及扩展 ...

  4. 如何在Cocos2D 1.0 中掩饰一个精灵(四)

    大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 为了完成需要的效果,我们将使用如下策略: 我们将首先绘制掩饰精灵 ...

  5. 【一天一道LeetCode】#94. Binary Tree Inorder Traversal

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...

  6. python的sys模块

    Sys模块函数之多,我只能选取自己认为比较实用的一些函数列在此处.借马云找员工的说法,"找最合适的而不是最天才的",这句话,我个人觉得在很多方面都能适应,学习也不在话下.Sys模块 ...

  7. Android studio使用git-android学习之旅(79)

    首先我参考了hello_my_show和梦痕_sky的博客,表示感谢 android studio对于git的支持是很好的,这节课我们拉讲解怎么使用git可视化工具来clone project和提交修 ...

  8. python模块:调用系统命令模块subprocess等

    http://blog.csdn.net/pipisorry/article/details/46972171 Python经常被称作"胶水语言",因为它能够轻易地操作其他程序,轻 ...

  9. AngularJS进阶(二十六)实现分页操作

    JS实现分页操作 前言 项目开发过程中,进行查询操作时有可能会检索出大量的满足条件的查询结果.在一页中显示全部查询结果会降低用户的体验感,故需要实现分页显示效果.受前面"JS实现时间选择插件 ...

  10. 我所理解的Android 启动模式

    首先,这是从 一个开源网站转载的,觉得写得不错,对我们之前理解的activity的启动模式是一个新的理解方式,并给出实际的应用场景. 任务栈是什么 任务栈Task,是一种用来放置Activity实例的 ...