Maison > Article > interface Web > Guide de développement pratique des directives dans AngularJS (1)_AngularJS
Les directives sont la partie la plus importante de toute application AngularJS. Bien qu'AngularJS fournisse déjà un ensemble de directives très riche, il est souvent nécessaire de créer des directives spécifiques à l'application. Ce didacticiel vous expliquera comment personnaliser les instructions et vous présentera comment les utiliser dans des projets réels. À la fin de cet article (partie 2), je vous expliquerai comment utiliser les directives angulaires pour créer une application de bloc-notes simple.
Aperçu
Une directive utilisée pour introduire une nouvelle syntaxe HTML. Les directives sont des balises sur les éléments DOM qui font que l'élément a un comportement spécifique. Par exemple, le HTML statique ne sait pas comment créer et afficher un contrôle de sélecteur de date. Pour que HTML reconnaisse cette syntaxe, nous devons utiliser des directives. La directive crée un élément qui prend en charge la sélection de date d'une manière ou d'une autre. Nous expliquerons comment cela se fait étape par étape. Si vous avez déjà écrit une application AngularJS, vous avez certainement utilisé des directives, que vous en ayez conscience ou non. Vous devez avoir utilisé des commandes simples telles que ng-mode, ng-repeat, ng-show, etc. Ces directives donnent des comportements spécifiques aux éléments du DOM. Par exemple, ng-repeat répète un élément spécifique et ng-show affiche un élément de manière conditionnelle. Si vous souhaitez qu'un élément prenne en charge le glisser, vous devez également créer une directive pour l'implémenter. L'idée de base de la directive est simple. Il rend le HTML véritablement interactif en liant les écouteurs d'événements aux éléments ou en modifiant le DOM.
perspective jQuery
Imaginez comment créer un sélecteur de date à l'aide de jQuery. Tout d’abord, nous ajoutons une zone de saisie normale au HTML, puis utilisons jQuery pour appeler $(element).dataPicker() pour la convertir en sélecteur de date. Mais réfléchissez-y. Lorsqu’un concepteur vient examiner le balisage HTML, peut-il immédiatement deviner ce que représente réellement ce champ ? S'agit-il simplement d'une simple zone de saisie ou d'un sélecteur de date ? Vous devrez examiner le code jQuery pour les déterminer. L'approche d'Angular consiste à utiliser une directive pour étendre le HTML. Ainsi, une directive de sélecteur de date peut être de la forme suivante :
<input type="text" />
Ou ceci :
<input type="text" />
Cette façon de créer des composants d'interface utilisateur est plus directe et plus claire. Vous pouvez facilement comprendre de quoi il s’agit en regardant les éléments.
Créez une directive personnalisée :
Une directive Angular peut avoir les quatre formes d'expression suivantes : 1. Un nouvel élément HTML (bd58549bf2658b48e28c17c1c4032335208fc95a7811bc2ac6e9f365abba8b59) 2. Les attributs de l'élément (d3299ce2158f2909f25766172d767b31) 3. Classe CSS (88241ada37d735f02ff0ec00bad2dd58) 4. Commentaire (35c250549fd6f58485515c3bb70d7bbd) De Bien sûr, nous pouvons contrôler la façon dont nos directives apparaissent en HTML. Voyons comment écrire une directive typique dans AngularJS. L'enregistrement des directives se fait de la même manière qu'un contrôleur, mais il renvoie un objet simple (objet de définition de directive) avec des propriétés de configuration de directive. Le code ci-dessous est une simple directive Hello World.
var app = angular.module('myapp', []); app.directive('helloWorld', function() { return { restrict: 'AE', replace: 'true', template: '<h3>Hello World!!</h3>' }; });
Dans le code ci-dessus, la méthode app.directive() enregistre une nouvelle directive dans le module. Le premier paramètre de cette méthode est le nom de la directive. Le deuxième paramètre est une fonction qui renvoie l'objet de définition de directive. Si votre directive dépend d'autres objets ou services, tels que $rootScope, $http ou $compile, ils peuvent être injectés à ce moment-là. Cette directive est utilisée comme élément en HTML, comme suit :
<hello-world/> //OR <hello:world/>
Ou utilisez-le comme attribut :
<div hello-world></div> //OR <div hello:world/>
Si vous souhaitez vous conformer aux spécifications HTML5, vous pouvez ajouter le préfixe x- ou data- devant l'élément. Ainsi, la balise suivante correspondra également à la directive helloWorld :
<div data-hello-world></div> //OR <div x-hello-world></div>
注意: 在匹配指令的时候,Angular会在元素或者属性的名字中剔除 x- 或者 data- 前缀。 然后将 – 或者 : 连接的字符串转换成驼峰(camelCase)表现形式,然后再与注册过的指令进行匹配。这是为什么,我们在HTML中以 hello-world 的方式使用 helloWorld 指令。其实,这跟HTML对标签和属性不区分大小写有关。 尽管上面的指令仅仅实现了静态文字的显示,但是这里还是有一些有趣的点值得我们去挖掘。我们在指令定义过程中使用了三个属性来配置指令。我们来一一介绍他们的作用。
restrict – 这个属性用来指定指令在HTML中如何使用(还记得之前说的,指令的四种表示方式吗)。在上面的例子中,我们使用了 ‘AE'。所以这个指令可以被当作新的HTML元素或者属性来使用。如果要允许指令被当作class来使用,我们将 restrict 设置成 ‘AEC'。
template – 这个属性规定了指令被Angular编译和链接(link)后生成的HTML标记。这个属性值不一定要是简单的字符串。template 可以非常复杂,而且经常包含其他的指令,以及表达式({{ }})等。更多的情况下你可能会见到 templateUrl, 而不是 template。所以,理想情况下,你应该将模板放到一个特定的HTML文件中,然后将 templateUrl 属性指向它。
replace – 这个属性指明生成的HTML内容是否会替换掉定义此指令的HTML元素。在我们的例子中,我们用 edd05d9b720c954eda8df66606fc7d416d95f50462131a27fde32c4d9df5bdd4的方式使用我们的指令,并且将 replace 设置成 true。所以,在指令被编译之后,生成的模板内容替换掉了 edd05d9b720c954eda8df66606fc7d416d95f50462131a27fde32c4d9df5bdd4。最终的输出是 684271ed9684bde649abda8831d4d355Hello World!!39528cedfa926ea0c01e69ef5b2ea9b0。如果你将 replace 设置成 false,也就是默认值,那么生成的模板会被插入到定义指令的元素中。
打开这个 plunker,在”Hello World!!”右键检查元素内容,来更形象地明白这些。
Link函数和Scope
指令生成出的模板其实没有太多意义,除非它在特定的scope下编译。默认情况下,指令并不会创建新的子scope。更多的,它使用父scope。也就是说,如果指令存在于一个controller下,它就会使用这个controller的scope。 如何运用scope,我们要用到一个叫做 link 的函数。它由指令定义对象中的link属性配置。让我们来改变一下我们的 helloWorld 指令,当用户在一个输入框中输入一种颜色的名称时,Hello World 文字的背景色自动发生变化。同时,当用户在 Hello World 文字上点击时,背景色变回白色。 相应的HTML标记如下:
<body ng-controller="MainCtrl"> <input type="text" ng-model="color" placeholder="Enter a color" /> <hello-world/> </body>
修改后的 helloWorld 指令如下:
app.directive('helloWorld', function() { return { restrict: 'AE', replace: true, template: '<p style="background-color:{{color}}">Hello World', link: function(scope, elem, attrs) { elem.bind('click', function() { elem.css('background-color', 'white'); scope.$apply(function() { scope.color = "white"; }); }); elem.bind('mouseover', function() { elem.css('cursor', 'pointer'); }); } }; });
我们注意到指令定义中的 link 函数。 它有三个参数:
scope – 指令的scope。在我们的例子中,指令的scope就是父controller的scope。
elem – 指令的jQLite(jQuery的子集)包装DOM元素。如果你在引入AngularJS之前引入了jQuery,那么这个元素就是jQuery元素,而不是jQLite元素。由于这个元素已经被jQuery/jQLite包装了,所以我们就在进行DOM操作的时候就不需要再使用 $()来进行包装。
attr – 一个包含了指令所在元素的属性的标准化的参数对象。举个例子,你给一个HTML元素添加了一些属性:,那么可以在 link 函数中通过 attrs.someAttribute 来使用它。
link函数主要用来为DOM元素添加事件监听、监视模型属性变化、以及更新DOM。在上面的指令代码片段中,我们添加了两个事件, click,和 mouseover。click 处理函数用来重置 e388a4556c0f65e1904146cc1a846bee 的背景色,而 mouseover 处理函数改变鼠标为 pointer。在模板中有一个表达式 {{color}},当父scope中的 color 发生变化时,它用来改变 Hello World 文字的背景色。 这个 plunker 演示了这些概念。
compile函数
compile 函数在 link 函数被执行之前用来做一些DOM改造。它接收下面的参数:
tElement – 指令所在的元素
attrs – 元素上赋予的参数的标准化列表
要注意的是 compile 函数不能访问 scope,并且必须返回一个 link 函数。但是如果没有设置 compile 函数,你可以正常地配置 link 函数,(有了compile,就不能用link,link函数由compile返回)。compile函数可以写成如下的形式:
app.directive('test', function() { return { compile: function(tElem,attrs) { //do optional DOM transformation here return function(scope,elem,attrs) { //linking function here }; } }; });
大多数的情况下,你只需要使用 link 函数。这是因为大部分的指令只需要考虑注册事件监听、监视模型、以及更新DOM等,这些都可以在 link 函数中完成。 但是对于像 ng-repeat 之类的指令,需要克隆和重复 DOM 元素多次,在 link 函数执行之前由 compile 函数来完成。这就带来了一个问题,为什么我们需要两个分开的函数来完成生成过程,为什么不能只使用一个?要回答好这个问题,我们需要理解指令在Angular中是如何被编译的!
指令是如何被编译的
当应用引导启动的时候,Angular开始使用 $compile 服务遍历DOM元素。这个服务基于注册过的指令在标记文本中搜索指令。一旦所有的指令都被识别后,Angular执行他们的 compile 方法。如前面所讲的,compile 方法返回一个 link 函数,被添加到稍后执行的 link 函数列表中。这被称为编译阶段。如果一个指令需要被克隆很多次(比如 ng-repeat),compile函数只在编译阶段被执行一次,复制这些模板,但是link 函数会针对每个被复制的实例被执行。所以分开处理,让我们在性能上有一定的提高。这也说明了为什么在 compile 函数中不能访问到scope对象。 在编译阶段之后,就开始了链接(linking)阶段。在这个阶段,所有收集的 link 函数将被一一执行。指令创造出来的模板会在正确的scope下被解析和处理,然后返回具有事件响应的真实的DOM节点。
改变指令的Scope
默认情况下,指令获取它父节点的controller的scope。但这并不适用于所有情况。如果将父controller的scope暴露给指令,那么他们可以随意地修改 scope 的属性。在某些情况下,你的指令希望能够添加一些仅限内部使用的属性和方法。如果我们在父的scope中添加,会污染父scope。 其实我们还有两种选择:
一个子scope – 这个scope原型继承子父scope。
一个隔离的scope – 一个孤立存在不继承自父scope的scope。
这样的scope可以通过指令定义对象中 scope 属性来配置。下面的代码片段是一个例子:
app.directive('helloWorld', function() { return { scope: true, // use a child scope that inherits from parent restrict: 'AE', replace: 'true', template: '<h3>Hello World!!</h3>' }; });
上面的代码,让Angular给指令创建一个继承自父socpe的新的子scope。 另外一个选择,隔离的scope:
app.directive('helloWorld', function() { return { scope: {}, // use a new isolated scope restrict: 'AE', replace: 'true', template: '<h3>Hello World!!</h3>' }; });
这个指令使用了一个隔离的scope。隔离的scope在我们想要创建可重用的指令的时候是非常有好处的。通过使用隔离的scope,我们能够保证我们的指令是自包含的,可以被很容易的插入到HTML应用中。 它内部不能访问父的scope,所保证了父scope不被污染。 在我们的 helloWorld 指令例子中,如果我们将 scope 设置成 {},那么上面的代码将不会工作。 它会创建一个新的隔离的scope,那么相应的表达式 {{color}} 会指向到这个新的scope中,它的值将是 undefined. 使用隔离的scope并不意味着我们完全不能访问父scope的属性。其实有一些技术可以允许我们访问父scope的属性,甚至监视他们的变化。我们会在指令这个系列的第二部分中讨论这些技术,以及一些更高级的概念,比如 Controller 函数。 第二部分也会和你一起使用Angular指令创建一个较为丰富的记事本应用。
关于AngularJS 中的指令实践指南(一),小编就给大家介绍到这里,下面文章讲给大家介绍angularjs中的指令实践开发指南二(二),希望对大家有所帮助!