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 ,很好学。
希望自己越来越厉害,全能型人才即将诞生。哈哈哈哈!!
 
 
posted @ 2015-09-01 10:11  不得不爱xxy  阅读(1087)  评论(3编辑  收藏  举报