紧接上篇“AngularJS 初步认识”http://www.linuxidc.com/Linux/2016-08/134158.htm
在AngularJS中指令尤为重要且内容庞多,固单独提炼出来,梳理一番。如有错误,请不吝讲解。好了,言归正传,让我们一起走进Angular指令的世界。在上篇文章的前言部分提到,Angular的核心就是对HTML标签的增强。我们用到的诸如ng-app、ng-controller等等这些都是属于Angular指令,具体点,它们为Angular内置的指令。Angular不仅提供了内置指令,它还允许我们自定义指令,不然Angular就太low咯。这也是本篇文章的核心:如何自定义指令。
Angular为我们提供了.directive()这个方法,来定义指令。
如下:正如上述代码所示,directive方法接受两个参数:name和factory_function。 --name嘛,即为指令的名字,供我们调用时使用; --factory_function就是当我们调用指令时,指令的实际行为,并且factory_function通常返回一个对象,里面通过规定的设置项来定义指令。那么自定义指令中,我们都可以操作哪些设置项呢?
如下:var app = angular.module("myApp", []);app.directive("myDirective", function(){return {restrict: "EACM",//告诉AngularJS这个指令在DOM中以何种形式被声明,默认为Apriority: Number,//优先级参数(值为数值),数值越大,优先级越高,默认为0terminal: Boolean,//true或者false,告诉AngularJS是(true)否(false)停止运行当前元素上比本指令优先级低的指令template: String or Template Function,//模板templateUrl: String,//模板URLreplace: Boolean,//值为true,代表模板会替换掉调用该指令的元素scope: Boolean or Object,//指令作用域transclude: Boolean,//true,结合ng-transclude,在该指令中嵌入内容controller: String or function($scope, $element, $attrs, $transclude, otherInjectables){...},//指令控制器controllerAs: String,//用来设置控制器的别名require: String,//将控制器注入到其值所指定的指令中link: function(scope, element, attrs){...},compile: function(){} };});代码稍长,请自行打开针对如此众多的设置项,我们一同先挑几个常用且简单的设置项,感受感受吧。
--template & templateUrl--template模板参数是可选的,其值可以是一段HTML文本,也可以是一个接受两个参数的函数。
注:如果template值为空,或者没有template设置项,那么不会覆盖嵌入在指令内部的元素,且当指令scope为false或者{…}时,内部元素的作用域共享外部父作用域;但,当指令scope为true时,内部元素的作用域就是继承自外部父作用域。
demo如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myModule">outterDirective:<input type="text" ng-model="name"/><br><one>innerDirective: <input type="text" ng-model="name"/></one><script src="angular.js"></script><script>var myModule = angular.module("myModule", []);myModule.directive("one", function(){return {scope: false,restrict: "E"}});</script></body></html>scope为false
效果图如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myModule">outterDirective:<input type="text" ng-model="name"/><br><one>innerDirective: <input type="text" ng-model="name"/></one><script src="angular.js"></script><script>var myModule = angular.module("myModule", []);myModule.directive("one", function(){return {scope: {},restrict: "E"}});</script></body></html>scope为{...}scope:{...}效果同上<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myModule">outterDirective:<input type="text" ng-model="name"/><br><one>innerDirective: <input type="text" ng-model="name"/></one><script src="angular.js"></script><script>var myModule = angular.module("myModule", []);myModule.directive("one", function(){return {scope: true,restrict: "E"}});</script></body></html>scope为true
scope为true,效果图如下: 假设,设置了template后,当我们调用指令后,它会呈现在页面中。下面我们就来具体看看。1、当template值为一段HTML文本时,demo如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {template: "<div> <h1>Hi everyone!</h1> </div>"};});</script></body></html>EntireCode2、当template值为函数时,demo如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive title="Monkey"></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {/*值为函数时,接受两个参数tElement, tAttrs:tElement:使用此指令的元素tAttrs:实例的属性,它是一个由元素上所有的属性组成的集合,即对象*/template: function(tElement, tAttrs){var _html = "";_html +="<div>" + "Hi,"+tAttrs.title+"</div>";return _html;}};});</script></body></html>代码稍长,请自行打开利用template可以在指令中自定义我们需要的模板,但是随着模板的体积(代码量)不断变大时,在指令中利用template就显得很糟糕,故而,使用templateUrl引用外部模板,是更好的选择。
--restrict--restrict 是一个可选参数,它告诉AngularJS这个指令在DOM中以何种形式被调用。一共有四个选择且都为大写,不然没效果,默认为A(属性)。
A(属性):<div my-directive></div>
E(元素):<my-directive></my-directive>
C(类名):<div class="my-directive"></div>
M(注释)://以注释调用指令时,前后得有空格<!-- directive:my-directive -->这四个选项,可以单独使用,亦可混合使用。如:restrict: ‘EA’就代表可以用元素或者属性调用指令
--replace--replace是一个可选参数,值为Boolean类型,默认为false,代表模板会被当作子元素插入到调用此指令的元素内部。
如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {replace: false,template: "<div>Monkey</div>"};});</script></body></html>代码稍长,请自行打开
运行后,打开chrome调试器,结果如下: --replace值为true,即模板会替换掉调用指令的元素,如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {replace: true,template: "<div>Monkey</div>"};});</script></body></html>代码稍长,请自行打开
运行后,打开chrome调试器,结果如下: 且,当值为true时,template会替代调用指令的元素,固template中的值,必须只包含一个根节点,不然会报错,如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {replace: true,template: "<div>Monkey</div><h1>Dorie</h1>"};});</script></body></html>代码稍长,请自行打开
运行后,打开chrome调试器,报错如下:--transclude--transclude是一个可选参数,表示是否允许在指令中,嵌入内容。值为Boolean,默认值为false代表不允许在指令中嵌入内容,如果手动设置为true后,要结合ng-transclude指令使用,不然和false效果一样。下面我们一起来编写两个demo具体看看。<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive><span>需要嵌入内容</span></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {transclude: false,template: "<div>指令内容</div>"};});</script></body></html>transclude为false
运行代码,打开chrome调试器得下:我们再来看看transclude:true的情况,将上述代码中的transclude的值改为true后,运行代码。咦,我靠和上诉transclude:false的结果一样呢?哦,对了,虽然我们将transclude的值设为true了,但是要结合ng-transclude指令嘛,不然,你让人家嵌入内容往哪插呢?利用ng-transclude指令修改代码后,得下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><div my-directive><span>需要嵌入内容</span></div><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("myDirective", function(){return {transclude: true,template: "<div>指令内容</div><div ng-transclude></div>"};});</script></body></html>代码稍长,请自行打开
运行代码,打开chrome调试器,得下: 注:利用ng-transclude指令标记的元素中,不管有没有内容,都将等同于无内容情况。咦,利用transclude嵌入的内容,它们有自己的作用域吗?如果有,那么它们的作用域继承谁呢,指令or外部作用域?
答案:利用ng-transclude嵌入的内容的同时,会创建一个属于自己的作用域,即子作用域,且继承自外部作用域,并非指令。
--scope--scope参数是可选的,它是直接影响指令的作用域。该参数可以被设置为不同的三个值,分别代表三种不同的作用域,下面我们就来一一说明。1、scope: false当scope的值为false时,也就是默认状态,代表指令共享父作用域,即没有自己的作用域。
如下: <!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp">Parent:<input type="text" ng-model="name"/><directive-for-false></directive-for-false><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("directiveForFalse", function(){return {restrict: "E",scope: false,template: "<div>Child: <input type="text" ng-model="name"> </div>"};});</script></body></html>代码稍长,请自行打开
执行上述代码,效果图如下: 2、scope: true当scope的值为true时,代表指令会创建自己的作用域,且继承自父作用域。
如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp">Parent:<input type="text" ng-model="name"/><directive-for-true></directive-for-true><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("directiveForTrue", function(){return {restrict: "E",scope: true,template: "<div>Child: <input type="text" ng-model="name"> </div>"};});</script></body></html>代码稍长,请自行打开
执行上述代码,效果图如下:3、scope: {…}当scope的值为对象时,代表指令会切断与外界的联系,创建一个隔离的作用域,既不继承于父作用域,也不准内嵌的指令继承于自己。一起写个demo,感受下“隔离作用域”不继承于父作用域,如下:<!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp">Parent:<input type="text" ng-model="name"/><directive-for-obj></directive-for-obj><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("directiveForObj", function(){return {restrict: "E",scope: {},template: "<div>Child: <input type="text" ng-model="name"> </div>"};});</script></body></html>
执行上述代码,效果图如下: 至于“不准内嵌的指令继承于自己”,参考上面的
--transclude--那当我们将scope设置为对象后,就成了一个无人问津的作用域,这样非常适合我们写插件之类的,但,怎么与外界交互呢?这就涉及到所谓的绑定策略啦。
如下:| scope的绑定策略 |
| @ | 把当前属性作为字符串传递。你还可以绑定来自外层scope的值,在属性值中插入{{ }}即可。 |
| = | 与父scope中的属性进行双向绑定。 |
| & | 传递一个来自父scope的函数 |
下面,我们就针对上面的提示,逐个demo,感受体会下。1、@策略 <!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><input type="text" ng-model="name"/><directive-for-obj who="{{name}}" love="love Dorie"></directive-for-obj><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("directiveForObj", function(){return {restrict: "E",scope: {who:"@",what: "@love"},template: "<div><input type="text" ng-model="who"/> {{what}}</div>"};});</script></body></html>代码稍长,请自行打开
效果图,如下: 2、=策略 <!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><input type="text" ng-model="name"/><directive-for-obj who="name" love="love Dorie"></directive-for-obj><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.directive("directiveForObj", function(){return {restrict: "E",scope: {who:"=",what: "@love"},template: "<div><input type="text" ng-model="who"/> {{what}}</div>"};});</script></body></html>代码稍长,请自行打开
效果图,如下:3、&策略 <!DOCTYPE html><head><meta charset="utf-8"/></head><body ng-app="myApp"><input type="text" ng-model="name"/><directive-for-obj who="name" love="love Dorie" greet="sayWhat(wt, whr)"></directive-for-obj><script src="angular.js"></script><script>var app = angular.module("myApp", []);app.run(function($rootScope){$rootScope.sayWhat = function(what, where){alert("hello, "+what+" at "+where);}});app.directive("directiveForObj", function(){return {restrict: "E",scope: {who:"=",what: "@love",greet: "&"},template: "<div><input type="text" ng-model="who"/> {{what}}</div><button ng-click="greet({wt: who, whr: who})">click</button>"};});</script></body></html>EntireCode
--controller--controller参数可以是一个字符串或一个函数。
注:当设置为字符串时,会以该字符串的值为名字,到注册在应用中的控制器中查找,不管该指令的scope值是什么,如果应用中的控制器没有对应的控制器,则报错。在控制器中,是的,控制器,包括了指令以及注册在应用中的,可以注入一些特殊的服务,供其使用,如下:
| $scope | 与指令元素相关联的当前作用域 |
| $element | 当前指令对应的元素 |
| $attrs | 当前元素的属性组成的对象,如:<div id=”nav” name=”Monkey”></div>属性对象为:{id: ‘nav’,name: ‘Monkey’} |
并且,指令之间的控制器(controller)可以复用。怎么复用呢?这就需要结合下面将要介绍的require设置项啦。
--require--require参数可以被设置为字符串或数组,字符串代表另外一个指令的名字。Require会将控制器注入到其值所指定的指令中,并作为当前指令的链接函数(link)的第四个参数。用法如下:
| 没有前缀 | 指令会在自身提供的控制器中进行查找,如果找不到任何控制器,则会抛出一个error |
| ? | 如果在当前的指令没有找到所需的控制器,则会将null传给link连接函数的第四个参数 |
| ^ | 如果在当前的指令没有找到所需的控制器,则会查找父元素的控制器 |
| ?^ | 综合前面?和^ |
一些AngularJS相关文章链接:AngularJS权威教程 清晰PDF版 http://www.linuxidc.com/Linux/2015-01/111429.htm希望你喜欢,并分享我的工作~
带你走近AngularJS系列:
- 带你走近AngularJS - 基本功能介绍 http://www.linuxidc.com/Linux/2014-05/102140.htm
- 带你走近AngularJS - 体验指令实例 http://www.linuxidc.com/Linux/2014-05/102141.htm
- 带你走近AngularJS - 创建自定义指令 http://www.linuxidc.com/Linux/2014-05/102142.htm
如何在 AngularJS 中对控制器进行单元测试 http://www.linuxidc.com/Linux/2013-12/94166.htm在 AngularJS 应用中通过 JSON 文件来设置状态 http://www.linuxidc.com/Linux/2014-07/104083.htmAngularJS 之 Factory vs Service vs Provider http://www.linuxidc.com/Linux/2014-05/101475.htmAngularJS —— 使用 ngResource、RESTful APIs 和 Spring MVC 框架提交数据 http://www.linuxidc.com/Linux/2014-07/104402.htm
AngularJS 的详细介绍:请点这里
AngularJS 的下载地址:请点这里
本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-08/134159.htm