angularjs 属性绑定directive 属性怎么用

AngularJS:何时应该使用Directive、Controller、Service?
AngularJS:何时应该使用Directive、Controller、Service?
[摘要:AngularJS:什么时候应当应用Directive、Controller、Service? (那篇文章您们肯定要看,特别初教的人,好吗亲?) 大漠贫春 译 AngularJS是一款特别很是强盛的前端MVC框架。同时,它也引进了相称多的]
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 = {
{ 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.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 ) {
restrict: &A&,
link: function( scope, element, attrs ) {
element.bind( &click&, function() {
Book.addBook( { title: &Star Wars&, author: &George Lucas& } );
很简单的东西。我们创建了一个指令,它的核心目的是简单地向books列表中添加一本书籍,books已经注册在了我们的Book服务中。我们来把这个指令应用到我们的视图中。
add-book-buttonAdd book
如你所见,我们仅仅把指令当作一个元素属性来使用。每次点击这个按钮的时候,它都会把《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
Angular的模块依赖哲学无疑让它成为了一款非同凡响的框架。它让我们能够以这样一种方式来编写我们的前端代码:我们不会干翻自己,也不会干翻框架---这可能是它最强大的力量。
希望我已经充分说明了你应该在何时何地使用这几个Angular概念,从而能够更好地编写你自己的代码。
原文链接:
http://kirkbushell.me/when-to-use-directives-controllers-or-services-in-angular/
其它相关内容:
1、《AngularJS》一书已经由电子工业出版社出版
/blog/1965167
2、《AngularJS》5个实例详解Directive(指令)机制
/blog/1917971
3、AngularJS表单基础
/blog/1920191
4、AngularJS Form 进阶:远程校验和自定义输入项
/blog/1920993
5、AngularJS:在Windows上安装Yeoman
/blog/1885371
6、对比Angular/jQueryUI/Extjs:没有一个框架是万能的
/blog/1922004
7、使用JsTestDriver实现JavaScript单元测试
/blog/1924415
8、JavaScript单元测试系列二:将Jasmine集成到JsTestDriver
/blog/1925974
感谢关注 Ithao123Ruby频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊AngularJs开发——指令间的通信 》 html5jscss
2,436&阅读
指令之间通信,跟差不多,无非是也是几种方法:
通过指令自身参数
基于event传播的方式
service的方式
service的方式是实现控制器之间、指令与控制器之间,以及指令之间都可以使用的方法,使用方法也差不多,在注册指令或者控制器时,将依赖服务注入就就可以完成通信了。event 是scope作用域层级传播,所以理所当然用来解决控制器之间的通信,但是指令与控制器、指令之间再使用event,有点绕,很不优雅,所以指令间通信最好不要使用基于event。
通过指令自身参数,已经很完美得实现父子指令双向间通信和同级指令间通信,实现的关键是公用同一个scope实现双向绑定。
父子级指令间通信
指令相当于是一个模块,而 require 告诉指令自己运行需要引用另外一个指令(模块),定义在 controller 上就能把方法和属性怎么暴露出去。所以有使用require肯定会有controller,有使用controller不一定会使用到require。
require参数:
^:从父节点上寻找依赖的其他指令
?:告诉指令如果没有找到依赖的指令,不要抛出异常。
以上代码我们发现:
父指令 superset的scope:true,不能设置成单独的scope,不然子指令就不能父指令的scope。
暴露API:在父级指令中,把要暴露的属性定义在scope上,而暴露的方法则定义在this。
同级指令间通信
同级指令的通信更简单,将指令包在一个controller内,让那些指令都公用同一个scope,其实跟上面父子级通信方法原理是一样的。
本文源链接:转载请注明《》|
看过此文章的人还看过
热门标签&&.&.&.&&[译] AngularJS内幕详解之 Directive - w3ctech - 中国最大的前端技术社区
[译] AngularJS内幕详解之 Directive
Atwood.cai
原文作者:
在,我讨论了scope事件以及digest循环的行为。这一次,我将谈论指令。这篇文章包括 独立的scope,内嵌,link函数,编译器,指令控制器等等。
如果这个图表看起来非常的费解,那么这篇文章很适合你。
(Image credit: ) ()
声明: 这篇文字是基于 .
到底什么是指令(directive)?
AngularJS中,指令是 通常是小的 组件, 这意味着跟DOM交互。他经常被用作顶层DOM的抽象层,大多数的操作可以不用jQuery,jqLite等包装的DOM元素。通过使用表达式、其他的指令来得到你想要的结果是高明的。
在AngularJS的核心里,指令可以绑定元素的属性(例如可见性,class列表,内部文本,内部HTML或者值)到scope的属性或表达式。最值得注意的是,一旦监测到scope中的变化被标记,这些绑定就会被更新。反过来也是相似的,使用$observe函数能够监测DOM属性,当监测到属性变化时会触发一个回调。
简单的说,指令是AngularJS中很重要的一面。如果你精通指令,那么处理AngularJS程序你将不会有任何问题。同理,如果你不设法理解指令,你将很难将其用在合适的地方。熟练指令需要时间,尤其是你在尝试不仅仅是用jQuery封装代码就完事。
在AngularJS,你能够建立组件化的指令、服务和控制器,它们可以复用,只要复用是合理的。例如你有一个简单的指令,基于一个监测的scope表达式来切换class
,在你的代码中用来标识你的特定组件的状态,我想那是一个十分通用的指令,能够在你的程序里到处使用到。你可以有一个服务集成键盘快捷键的服务、控制器、指令和其他注册快捷键的服务,它支持所有键盘快捷键的处理在一个自包含的服务中。
指令也是可重用的功能,但经常被分配给 DOM 片段,或者模板,而不是仅仅提供功能。是时候深入了解 AngularJS 指令及其他的用法了。
创建一个指令
之前,我,我用他来解释 digest 机制以及 scope 如何操作的。 我会用同样的方式来解释指令, 但是这次我将剖析指令的工厂函数返回的对象的属性,以及每个这些属性如何影响我们所定义的指令。
首先要注意下指令的名字, 来看一个简单的例子。
angular.module('PonyDeli').directive('pieceOfFood', function () {
var definition = { //
尽管在上面的的代码片段中我们定义了一个命名为'pieceOfFood'的指令,AngularJS约定在 HTML 标记里使用破折号的形式连接名字。如果这个指令作为一个属性实现,那么我在 HTML 中就会像这样调用:
&span piece-of-food&&/span&
默认情况,指令只能作为属性被触发。但是如果你想改变这种方式,你可以使用 restrict 属性。
如何定义一个指令作为标签使用。
angular.module('PonyDeli').directive('pieceOfFood', function () {
restrict: 'E',
template: // ...
出于某种原因,我无法捉摸它们决定混淆什么,本来一个很有表达能力的框架,却以单个大写字母结尾来定义指令是如何被限制的。GitHub 上有一个列表, restrict 的
'A': attributes are allowed
'A': 允许作为一个属性&span piece-of-food&&/span&
'E': elements are allowed
'E': 允许作为一个元素&piece-of-food&&/piece-of-food&
'C': as a class name
'C': 作为一个类名&span class='piece-of-food'&&/span&
'M': as a comment
'M': 作为一个注释&!-- directive: piece-of-food --&
'AE': You can combine any of these to loosen up the restriction a bit.
'AE': 可以结合上面的任意值来放松限制。
千万别用 'C' 或者 'M' 来限制你的指令。 用 'C' 不能使之在标记中凸显出来, 用 'M' 是为了向后兼容。 如果你觉得有趣, 你可以用一个例子来设置 restrict 为 'ACME'。
不幸的是, 指令定义对象的其他属性是很难理解的。
如何设置一个指令与父级 scope 交互。
因为我们在之前的文章中大范围的谈论了 scope,知道如何正确地使用 scope 属性,所以不应为此感到痛苦。我们从默认值开始, scope: false,使作用域链保持不受影响:依照我在你将得到与元素相关联的所有作用域。
当你的指令不会和 scope有互动,保持作用域链不变显然是有用的,但这种情况很少发生。一种更常见有用的情景是,不改变作用域创建一个指令,给他一个作用域,实例化多次并且只跟一个scope属性交互———指令的名字。跟默认值restrict: 'A'结合是最有表达力的。(下面的代码)
angular.module('PonyDeli').directive('pieceOfFood', function () {
template: '{{pieceOfFood}}',
link: function (scope, element, attrs) {
attrs.$observe('pieceOfFood', function (value) {
scope.pieceOfFood =
&body ng-app='PonyDeli'&
&span piece-of-food='Fish & Chips'&&/span&
这里有几个值得注意的点我们还没讨论到。你将在后面的章节了解到 link 属性。 暂且想一下作为一个控制器如何操作每个实例化的指令。
在指令的链接函数里,我们可以获得元素上的属性集合。这个集合有一个特殊的方法,叫$observe(), 可以触发一个回调。没有监听属性变化时,属性永远不会对应到scope上,也无法绑定到我们的模板上。
我们可以改下上面的代码,通过引进scope.$eval,让他更可用。记得他是如何依靠scope被用来解析一个表达式的吗?看下面的代码帮助我们更好的理解()。
var deli = angular.module('PonyDeli', []);
deli.controller('foodCtrl', function ($scope) {
$scope.piece = 'Fish & Chips';
deli.directive('pieceOfFood', function () {
template: '{{pieceOfFood}}',
link: function (scope, element, attrs) {
attrs.$observe('pieceOfFood', function (value) {
scope.pieceOfFood = scope.$eval(value);
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&span piece-of-food='piece'&&/span&
这个例子中,通过 scope 我解析出了属性的值 piece,这个值定义在controller 中的 $scope.piece。当然,直接使用模板方式如{{piece},但是那样需要你特别注意你想追踪的scope属性。这种方式增加了一点灵活性,但当你想在在所有的指令间共享scope时, 如果你尝试用同样的scope添加多个指令则会导致意外的结果 。
好玩的子作用域
你可以创建一个子作用域来解决这个问题, 他继承自父级的原型。为了创建子作用域, 你仅仅需要声明 scope: true。
var deli = angular.module('PonyDeli', []);
deli.controller('foodCtrl', function ($scope) {
$scope.pieces = ['Fish & Chips', 'Potato Salad'];
deli.directive('pieceOfFood', function () {
template: '{{pieceOfFood}}',
scope: true,
link: function (scope, element, attrs) {
attrs.$observe('pieceOfFood', function (value) {
scope.pieceOfFood = scope.$eval(value);
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&p piece-of-food='pieces[0]'&&/p&
&p piece-of-food='pieces[1]'&&/p&
正如你所见,现在我们可以使用指令的多个实例来达到预期的效果,因为每个指令都创建了自己的作用域。 但是,这里有一个局限:一个元素的多个指令都是一个相同的作用域。
注意:如果同一元素的多个指令需要新的作用域,那么只会创建一个作用域。
独立的,隔绝的scope
最后一个选项是用来创建一个本地的,独立的作用域。独立的作用域跟子作用域不同在于前者不是继承自他的父级(但是也可以通过 scope.$parent 访问)。你可以像这样声明一个独立的作用域:scope: {}。你可以添加一些属性到这个对象,用来从父级scope获取数据绑定并且当前作用域也可访问。很像restrict,独立scope的属性简洁但语法复杂,你可以用符号例如:&,@ 和=来定义属性的绑定方式。
你可以省略属性名如果你打算使用你本地scope的属性名。那就是说,pieceOfFood: '=' 是 pieceOfFood: '=pieceOfFood'的简写;他们是相等的。
选择你的武器: @,& 或者=
那么,这些符号是什么意思?下面枚举的例子,可以帮助你破解他们
属性观察器: @
使用 @ 监测属性的结果。
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&p note='You just bought some {{type}}'&&/p&
deli.directive('note', function () {
template: '{{note}}',
note: '@'
这变化来更新本地scope。当然,用 @ 符号是更多的“AngularJS”。
deli.directive('note', function () {
template: '{{note}}',
scope: {},
link: function (scope, element, attrs) {
attrs.$observe('note', function (value) {
scope.note =
当指令的选项很复杂时,属性监测器很有用。如果我们想通过改变选项来改变指令的行为,我们自己写代码使用attrs.$observe创建检测,比AngularJS 内部去做更有意义,更快。
这个例子中,仅仅替换了 scope.note = value , 如上面的$observe操作所示,任何你想要添加到$watch监听上都应该这样写。
注意:请记住,当遇到 @时,我们谈论的是观察和属性,而不是绑定到父作用域。
表达式构造器: &
使用 & 提供一个
,他的上下文是父级作用域。
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&p note='&You just bought some & + type'&&/p&
deli.directive('note', function () {
template: '{{note()}}',
note: '&'
下面,我已经在link函数里扼要地实现一个相同的功能 ,这个例子中你看不到 & 。这个比用 @ 要长一点点,因为他 是的,也构建了一个可重用的功能。
deli.directive('note', function ($parse) {
template: '{{note()}}',
scope: {},
link: function (scope, element, attrs) {
var parentGet = $parse(attrs.note);
scope.note = function (locals) {
return parentGet(scope.$parent, locals);
真如我们所见,表达式构造器会生成了一个依赖父级scope的方法。你可以随时执行他,甚至可以监测到输出的变化。这个方法在父级scope应该作为只读的查询对待。这样在两种情况下非常有用,当你需要监听父级scope的变化时,这种情况下你应该在表达式函数 note()上设置一个监听, 本质上就像上面的例子。
另一种情况是, 当你需要访问父级scope方法时会派上用场。假设父级scope有一个方法用来更新一个 table,而你的本地 scope用来显示一个table的行。
如果按钮在子scope里,那么通过使用 & 绑定和使用父级scope的刷新方法是很有用的。这仅仅是个人的例子 —— 你或许更喜欢用事件来处理这类事情, 甚至用某种方式构造你的程序来避免一些复杂的事。
双向数据绑定:=
使用 = 设置 本地scope与父级scope间的双向数据绑定。
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&button countable='clicks'&&/button&
&span&Got {{clicks}} clicks!&/span&
deli.directive('countable', function () {
'' +
'Click me {{remaining}} more times! ({{count}})' +
'',
replace: true,
count: '=countable'
link: function (scope, element, attrs) {
scope.remaining = 10;
element.bind('click', function () {
scope.remaining--;
scope.count++;
scope.$apply();
双向数据绑定比 & 或者 @ 。
deli.directive('countable', function ($parse) {
'' +
'Click me {{remaining}} more times! ({{count}})' +
'',
replace: true,
scope: {},
link: function (scope, element, attrs) {
// you're definitely better off just using '&'
var parentGet = $parse(attrs.countable);
if (parentGet.literal) {
compare = angular.
compare = function(a,b) { return a === };
var parentSet = parentGet. // or throw
var lastValue = scope.count = parentGet(scope.$parent);
scope.$watch(function () {
var value = parentGet(scope.$parent);
if (!compare(value, scope.count)) {
if (!compare(value, lastValue)) {
scope.count =
parentSet(scope.$parent, value = scope.count);
return lastValue =
}, null, parentGet.literal);
// I told you!
scope.remaining = 10;
element.bind('click', function () {
scope.remaining--;
scope.count++;
scope.$apply();
这种形式的数据绑定可以说是最有用的。在这个例子中,父级scope属性与本地scope保持同步。任何时候的本地scope的值发生改变,都会设置到父级scope上。同样,任何时候的父级scope值改变了,本地scope也能更新。最直接有用的情形是,你有一个子scope用来展示父级scope的子模块。试想一个经典的table(增、删、改、查)。table作为一整个父级scope, 每个row 包含一个独立的指令用来双向绑定每行的数据模型。这样的模块化,仍然可以保持table和其孩子间的有效通信。
刚刚花了很多的文字,但是我认为我已经总结好了指令声明与scope属性如何工作以及最常见的使用方法。
敏锐的视图模板
当指令包含小的可重用的 HTML 代码片段时,指令变得非常高效, 这是指令的真正力量来源。 当手动启动指令时,这些模板可以作为纯文本
或AngularJS 查询的资源提供给指令。
以纯文本提供视图模板template: '&span ng-bind=&message& /&'
这样允许你提供一个链接作为 HTML模板templateUrl: /partials/message.html
用 templateUrl 将 HTML从你的 link函数中分开是很棒的。当指令第一次初始化时会发出一个AJAX请求。但是, 如果你构建任务提前填充到 $templateCache,就可以规避AJAX请求 例如。
你也可以用一个函数 function (tElement, tAttrs) 作为模板,但是这既不需要也不实用
模板应该作为子元素还是内联插入?
是可悲而混乱的:
specify where the template should be inserted. Defaults to false.
true — the template will replace the current element
false — the template will replace the contents of the current element
声明模板应该插入到什么地方。默认值是 false。
true —— 模板将替换当前的元素
false —— 模板将替换当前元素的内容
那么,当 replace: false, 指令实际上替换了元素? 这听起来是不对的。 如果你,你会发现如果 replace: false, 元素只是只是被追加, 如果 replace: true, 将会有序的替换元素。
根据经验,尽量保持替换到最低限度。当然,只要有可能,指令应该与DOM保持尽可能少的干扰。
指令被编译的结果是 pre-link 函数和 post-link函数。你可以自定义代码来返回这些函数或只是提供给他们。下面有两种方式来提供 link 函数。我提醒你:这又是另一个那些AngularJS“特色”, 我觉得更多的是一种缺点。 因为它只会使新人更加困惑,没有任何好处。
compile: function (templateElement, templateAttrs) {
pre: function (scope, instanceElement, instanceAttrs, controller) {
// pre-linking function
post: function (scope, instanceElement, instanceAttrs, controller) {
// post-linking function
compile: function (templateElement, templateAttrs) {
return function (scope, instanceElement, instanceAttrs, controller) {
// post-linking function
pre: function (scope, instanceElement, instanceAttrs, controller) {
// pre-linking function
post: function (scope, instanceElement, instanceAttrs, controller) {
// post-linking function
link: function (scope, instanceElement, instanceAttrs, controller) {
// post-linking function
事实上,你甚至可以忘掉关于指令定义的对象,我们到此讨论的只是返回后的 post-link 函数。但是,不建议 AngularJS 初学者掌握它, 最好远离它。注意,link函数中声明控制器或指令时不支持依赖注入。大多数情况下,AngularJS 的依赖注入在顶层API可用,但是大多数其他方法有封装好的静态参数列表,你不能改变。
deli.directive('food', function () {
return function (scope, element, attrs) {
// post-linking function
继续进行之前,有个 AngularJS 文档很重要的注意事项, 我希望你看看:
注意:如果模板被克隆了,模板实例和link实例可能是不同的对象。出于这点,在compile函数里,除了 转换那些可以被安全操作的克隆DOM节点外,都是不安全的。特别是,DOM监听器注册应该在link函数中,而不是compile函数中。
目前compile函数增加了第三个参数,一个嵌入(transclude)link函数,但是他被弃用了。同样的,你不应该在comiple函数执行期间操作DOM(templateElement)。为了编译完全,请帮忙直接提供 pre-link 函数和 post-link 函数。通常,一个post-link 函数就够了,即是你分配给定义对象的link函数。
我这里给你一条规则,始终使用post-link 函数。 如果一个 scope 一定要在 DOM链接之前填充好, 可以在pre-link 函数中操作,但是要在post-link 函数中绑定该功能,就像你正常的操作。你将很少需要这样做, 但是我认为值得你注意。
pre: function (scope, element, attrs, controller) {
scope.requiredThing = [1, 2, 3];
post: function (scope, element, attrs, controller) {
scope.squeal = function () {
scope.$emit(&squeal&);
这是一个指令的控制器实例。
指令可以有控制器,这说得通是因为指令可以创建 scope
。该控制器在所有的同一 scope 的指令中共享,同时可以作为 link 函数的第四个参数被访问到。在同一层级的scope上,这些控制器是指令间的一个可用的通信信道,也可能包含指令自身。
这是在模板中使用的 controller 别名
使用控制器别名允许你在模板里面引用控制器,因为他在 scope 中是可见的。
如果你没有链接其他的指令到某个元素上会抛出一个错误。
这里有个非常简单的 require 文档, 我就简单的复制在这:
Require another directive and inject its controller as the fourth argument to the linking function. The require takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the injected argument will be an array in corresponding order. If no such directive can be found, or if the directive does not have a controller, then an error is raised. The name can be prefixed with:
(no prefix) Locate the required controller on the current element. Throw an error if not found
? Attempt to locate the required controller or pass null to the link fn if not found
^ Locate the required controller by searching the element’s parents. Throw an error if not found
?^ Attempt to locate the required controller by searching the element’s parents or pass null to the link fn if not found
引入其他指令并注入到控制器中,并作为当前指令的链接函数的第四个参数。require使用字符串或数组元素来传入指令。如果是数组,注入的参数是一个相应顺序的数组。如果这样的指令没有被找到,或者该指令没有控制器, 就会报错。 require参数可以加一些前缀:
(没有前缀)如果没有前缀,指令将会在自身所提供的控制器中进行查找,如果没有找到任何控制器就抛出一个错误。
? 如果在当前指令中没有找到所需要的控制器,会将null作为传给link函数的第四个参数。
^ 如果添加了^前缀,指令会在上游的指令链中查找require参数所指定的控制器。
?^ 将前面两个选项的行为组合起来,我们可选择地加载需要的指令并在父指令链中进行查找。
在我们的工作中,如果我们的指令需要依赖其他的指令时,require 很有用。 举个例子, 你或许有个 dropdown 指令,他依赖一个 list-view 指令, 或者一个错误弹框的指令依赖一个错误消息指令。在下面的例子中,反过来说,定义一个 needs-model 指令,
如果他没有找到依赖的 ng-model 就会抛出一个错误 —— 因为 needs-model指令使用了那个指令,或者某种程度上取决于他在元素上可用。
angular.module('PonyDeli').directive(‘needsModel’, function () {
require: 'ngModel’,
&div needs-model ng-model=’foo’&&/div&
priority 定义了指令执行的顺序。
When there are multiple directives defined on a single DOM element, sometimes it is necessary to specify the order in which the directives are applied. The priority is used to sort the directives before their compile functions get called. Priority is defined as a number. Directives with greater numerical priority are compiled first. Pre-link functions are also run in priority order, but post-link functions are run in reverse order. The order of directives with the same priority is undefined. The default priority is 0.
当一个DOM元素上定义了多个指令时,有时指定指令的执行顺序很有必要。指令在未调用compile函数前根据priority排序。 priority 被定义为一个数字。拥有大数字的priority的指令先执行。 pre-link函数也按照priority顺序执行,但是post-link 函数按照相反的顺序执行。 相同优先级的指令顺序是 undefined 。priority 的默认值是 0.
terminal 防止指令进一步执行。
If set to true then the current priority will be the last set of directives which will execute (any directives at the current priority will still execute as the order of execution on same priority is undefined).
如果terminal设置为 true, 那么当前优先级的指令就是当前元素的指令集的最后一个可执行的(任何比当前优先级高的指令都会按照顺序执行, 相同优先级的顺序是undefined)。
Transcluding For Much Win
对元素内容的编译和指令中使其可用。
这个属性允许两个值。你可以设置为 true 允许嵌套;也可以设置为 'element',这种情况下整个元素,包括一些低优先定义的级指令, 都被嵌入。
更高的水平是,嵌套允许指令的使用自定义的 HTML 片段,用 ng-transclude 指令嵌入到指令的一部分。这听起来复杂,举个例子:
angular.module('PonyDeli').directive('transclusion', function () {
restrict: 'E',
'&div ng-hide=&hidden& class=&transcluded&&' +
'&span ng-transclude&&/span&' +
'&span ng-click=&hidden=true& class=&close&&Close&/span&' +
'&/div&',
transclude: true
&body ng-app='PonyDeli'&
&transclusion&
&span&The plot thickens!&/span&
&/transclusion&
你可以。 当你尝试在混合后获取scope时会发生什么? 指令里获取嵌入的内容总是从父级内容响应,即使在指令中被替换,即使指令的呈现出一个独立的scope。这正是你期待的,因为嵌入内容定义在销毁的内容,他属于父级scope,而不是指令的scope。指令依然绑定的是本地scope。
var deli = angular.module('PonyDeli', []);
deli.controller('foodCtrl', function ($scope) {
$scope.message = 'The plot thickens!';
deli.directive('transclusion', function () {
restrict: 'E',
'&div ng-hide=&hidden& class=&transcluded&&' +
'&span ng-transclude&&/span&' +
'&span ng-click=&hidden=true& class=&close& ng-bind=&close&&&/span&' +
'&/div&',
transclude: true,
scope: {},
link: function (scope) {
scope.close = 'Close';
&body ng-app='PonyDeli' ng-controller='foodCtrl'&
&transclusion&
&span ng-bind='message'&&/span&
&/transclusion&
“,” Nicolas Bevacqua, Smashing Magazine
“,” StackOverflow
“” (screencast), John Lindquist, Egghead.io
“,” StackOverflow
“,” Liam Kaufman
扫码关注w3ctech微信公众号
只有w3ctech成员才能发表和回复。
后发表或回复!
只有w3ctech成员才能发表和回复。
后发表或回复!

我要回帖

更多关于 angularjs directive 的文章

 

随机推荐