AngularJS开发之_指令
指令是什么? 指令是我们用来扩展浏览器能力的技术之一。在DOM编译期间,和HTML关联着的指令会被检测到,并且被执行。这使得指令可以为DOM指定行为,或者改变它。
1.指令的匹配模式
index.html :
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 </head> 6 <body> 7 <hello></hello> 8 <div hello></div> 9 <div class="hello"></div> 10 <!-- directive:hello --> 11 <div></div> 12 </body> 13 <script src="framework/angular-1.3.0.14/angular.js"></script> 14 <script src="HelloAngular_Directive.js"></script> 15 </html>
helloAngular_Directive.js :
1 var myModule = angular.module("MyModule", []); 2 myModule.directive("hello", function() { 3 return { 4 restrict: 'AEMC', 5 template: '<div>Hi everyone!</div>', 6 replace: true 7 } 8 });
html中包含五个元素,其中一个是注释的元素,JS中定义了一个模块和模块的指令。
OK,不要急,先来看一下 directive 是什么意思,directive的意思是指令,顾名思义,定义一个指令,名字叫 “hello”.
首先,看一下 restrict , restrict的意思是限制,约束。也就是要讲的指令的匹配模式,共有四种:
(1)E: 元素(即html中的<hello></hello>);
(2)A(默认) :属性 (<div hello></div>);
(3)C: 样式类(<div class="hello"></div>)
(4)M: 注释(<!-- directive:hello -->)
常用 A E , 推荐使用这两个。下图就是匹配到的指令元素,并替换了元素的内容,至于怎么替换的内容,继续往下看。
接下来,看一下 template ,template的意思是模板,也就是要替换的内容。但是在js中组织和拼接div这些元素的代码,很费劲的。怎么办呢。有办法,那就是 templateUrl, 把要替换的元素内容写到一个页面里面。嗯如下所示:
1 var myModule = angular.module("MyModule", []); 2 myModule.directive("hello", function() { 3 return { 4 restrict: 'AECM', 5 templateUrl: 'hello.html', 6 replace: true 7 } 8 });
如果我们想要在别的指令中也是用这个hello.html怎么办,那么就有出现了一个缓存的解决办法。看下面的 run 方法在加载完所有模块后,只执行一次,然后把模板缓存起来,当有指令需要调用时,就调用 $templateCache.get().
1 var myModule = angular.module("MyModule", []); 2 //注射器加载完所有模块时,此方法执行一次 3 myModule.run(function($templateCache){ 4 $templateCache.put("hello.html","<div>Hello everyone!!!!!!</div>"); 5 }); 6 myModule.directive("hello", function($templateCache) { 7 return { 8 restrict: 'AECM', 9 template: $templateCache.get("hello.html"), 10 replace: true 11 } 12 });
接下来,再看一下 replace(”替换“),replace:true 会替换元素的内容。但是不想替换内容只是想添加一个内容呢,,没事,,还有 transclude
1 var myModule = angular.module("MyModule", []); 2 myModule.directive("hello", function() { 3 return { 4 restrict:"AE", 5 transclude:true, 6 template:"<div>Hello everyone!<div ng-transclude></div></div>" 7 } 8 });
最后介绍一下AngularJS的运行机制:
2.指令和控制器的交互。
index.html :
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 </head> 6 <body> 7 <div ng-controller="MyCtrl"> 8 <loader howToLoad="loadData()">滑动加载</loader> 9 </div> 10 <div ng-controller="MyCtrl2"> 11 <loader howToLoad="loadData2()">滑动加载</loader> 12 </div> 13 </body> 14 <script src="framework/angular-1.3.0.14/angular.js"></script> 15 <script src="Directive&Controller.js"></script> 16 </html>
Directive&Controller.js :
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.loadData=function(){ 4 console.log("加载数据中..."); 5 } 6 }]); 7 myModule.controller('MyCtrl2', ['$scope', function($scope){ 8 $scope.loadData2=function(){ 9 console.log("加载数据中...22222"); 10 } 11 }]); 12 myModule.directive("loader", function() { 13 return { 14 restrict:"AE", 15 link:function(scope,element,attrs){ 16 element.bind('mouseenter', function(event) { 17 //(1)scope.loadData(); 18 //(2)scope.$apply("loadData()"); 19 // 注意这里的坑,howToLoad会被转换成小写的howtoload 20 scope.$apply(attrs.howtoload); 21 }); 22 } 23 } 24 });
现在我们想要实现的效果是当鼠标滑过div元素时,调用一个加载数据的方法。
hmtl中我们定义了两个控制器,然后两个控制器中都使用了loader指令,并且,每个指令中都有一个参数 howToLoad .
关于指令中的 link ,上面介绍运行机制是已经看到了,是用来操作dom和绑定监听事件的。link中会有三个参数:scope(指令所属的控制器中的 $scope 对象)、element(指令所属dom元素)、attrs(dom元素所传的参数,如howToLoad 参数给的值 loadData()).
然后对于如何调用所需函数,有两种方法:
(1)scope.loadData() ,这种方法是有局限的,如,MyCtrl1 控制器中的指令所调用的方法是MyCtrl1控制器中所定义的loadData() 方法,但是MyCtrl2就会报错了,因为没有loadData(). 所有就有了另个一个方法。
(2)scope.$apply() , $apply()方法会从所有控制器中找到多对应的方法。这就实现了指令的复用。
3.指令间的交互。
index.html :
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <link rel="stylesheet" href="css/bootstrap-3.0.0/css/bootstrap.css"> 6 <script src="framework/angular-1.3.0.14/angular.js"></script> 7 <script src="Directive&Directive.js"></script> 8 </head> 9 <body> 10 <div class="row"> 11 <div class="col-md-3"> 12 <superman strength>动感超人---力量</superman> 13 </div> 14 </div> 15 <div class="row"> 16 <div class="col-md-3"> 17 <superman strength speed>动感超人2---力量+敏捷</superman> 18 </div> 19 </div> 20 <div class="row"> 21 <div class="col-md-3"> 22 <superman strength speed light>动感超人3---力量+敏捷+发光</superman> 23 </div> 24 </div> 25 </body> 26 </html>
Directive&Directive.js :
1 var myModule = angular.module("MyModule", []); 2 myModule.directive("superman", function() { 3 return { 4 scope: {},//独立作用域 5 restrict: 'AE', 6 controller: function($scope) { 7 $scope.abilities = []; 8 this.addStrength = function() { 9 $scope.abilities.push("strength"); 10 }; 11 this.addSpeed = function() { 12 $scope.abilities.push("speed"); 13 }; 14 this.addLight = function() { 15 $scope.abilities.push("light"); 16 }; 17 }, 18 link: function(scope, element, attrs) { 19 element.addClass('btn btn-primary'); 20 element.bind("mouseenter", function() { 21 console.log(scope.abilities); 22 }); 23 } 24 } 25 }); 26 myModule.directive("strength", function() { 27 return { 28 require: '^superman', 29 link: function(scope, element, attrs, supermanCtrl) { 30 supermanCtrl.addStrength(); 31 } 32 } 33 }); 34 myModule.directive("speed", function() { 35 return { 36 require: '^superman', 37 link: function(scope, element, attrs, supermanCtrl) { 38 supermanCtrl.addSpeed(); 39 } 40 } 41 }); 42 myModule.directive("light", function() { 43 return { 44 require: '^superman', 45 link: function(scope, element, attrs, supermanCtrl) { 46 supermanCtrl.addLight(); 47 } 48 } 49 });
定义了一个superman的指令和另外三个指令,分别是strength、speed、light、
后面三个指令都有一个 require 参数,是指都依赖superman指令,link中的最后一个参数就是superman指令的引用。
4.scope("作用域") 的绑定策略。
scope的绑定策略有三种:
(1)@ :把当前属性作为字符串传值。还可以绑定来自外层scope的值,在属性值中插入{{}}即可。
(2)= :与父scope中的属性进行双向绑定。
(3)& :传递一个来自父scope的函数,稍后调用。
index.html :
1 <!doctype html> 2 <html ng-app="MyModule"> 3 <head> 4 <meta charset="utf-8"> 5 <link rel="stylesheet" href="css/bootstrap-3.0.0/css/bootstrap.css"> 6 </head> 7 <body> 8 <div ng-controller="MyCtrl"> 9 <drink flavor="{{ctrlFlavor}}"></drink> 10 </div> 11 </body> 12 <script src="framework/angular-1.3.0.14/angular.js"></script> 13 <script src="ScopeAt.js"></script> 14 </html>
ScopeAt.js :
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.ctrlFlavor="百威"; 4 }]) 5 myModule.directive("drink", function() { 6 return { 7 restrict:'AE', 8 scope:{ 9 flavor:'@' 10 }, 11 template:"<div>{{flavor}}</div>" 12 //, 13 //link:function(scope,element,attrs){ 14 // scope.flavor=attrs.flavor; 15 //} 16 } 17 });
使用link进行指令和控制器两个作用域中数据的绑定。如果用scope中@的话,就不需要link这么麻烦了,angularJS会自动进行绑定。
接下来看scope 的 ”=“ 绑定策略:
1 <div ng-controller="MyCtrl"> 2 Ctrl: 3 <br> 4 <input type="text" ng-model="ctrlFlavor"> 5 <br> 6 Directive: 7 <br> 8 <drink flavor="ctrlFlavor"></drink> 9 </div>
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.ctrlFlavor="百威"; 4 }]) 5 myModule.directive("drink", function() { 6 return { 7 restrict:'AE', 8 scope:{ 9 flavor:'=' 10 }, 11 template:'<input type="text" ng-model="flavor"/>' 12 } 13 });
这个例子中有两个输入框,第一个绑定了MyCtrl控制器中的scope对象的ctrlFlavor 属性。第二个绑定的是指令中的flavor属性。 但是在drink 指令中 scope对象的flavor 属性 用了 ”=“ ,与父scope中的属性进行双向数据绑定。所以两个值有一个改动,另一个属性值也会改动。
最后来看一下 scope 的 ”&“ 绑定策略:
index.html :
1 <body> 2 <div ng-controller="MyCtrl"> 3 <greeting greet="sayHello(name)"></greeting> 4 <greeting greet="sayHello(name)"></greeting> 5 <greeting greet="sayHello(name)"></greeting> 6 </div> 7 </body>
1 var myModule = angular.module("MyModule", []); 2 myModule.controller('MyCtrl', ['$scope', function($scope){ 3 $scope.sayHello=function(name){ 4 alert("Hello "+name); 5 } 6 }]) 7 myModule.directive("greeting", function() { 8 return { 9 restrict:'AE', 10 scope:{ 11 greet:'&' 12 }, 13 template:'<input type="text" ng-model="userName" /><br/>'+ 14 '<button class="btn btn-default" ng-click="greet({name:userName})">Greeting</button><br/>' 15 } 16 });
点击按钮 会调用greet()函数,在前面html中已经指定了greet要绑定sayHello()函数,函数的参数来绑定 ng-model 的 输入框。
4.AngularJS内置指令。
不同版本的内置指令数目不同,详细的看官方API(----api----)
5.Angular-UI。
复杂的指令终于结束了,Angular-UI封装了很多好的指令可以直接使用。省得自己挨个再写,费劲。关于详细的一些指令的用法,多看看API ,很好学。
希望自己越来越厉害,全能型人才即将诞生。哈哈哈哈!!