跟我学AngularJs:Directive指令用法解读(下)

此文接 跟我学AngularJs:Directive指令用法解读(上)

8.transclude
 如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了<div>hello every <div>这是指令内部的内容</div></div>。默认值为false;这个配置选项可以让我们提取包含在指令那个元素里面的内容,再将它放置在指令模板的特定位置。当你开启transclude后,你就可以使用ng-transclude来指明了应该在什么地方放置transcluded内容
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html lang="zh" ng-app="myApp">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>AngularJS入门学习</title>  
  6.     <script type="text/javascript" src="./1.5.3/angular.min.js"></script>  
  7. </head>  
  8. <div sidebox title="Links">  
  9.          <ul>  
  10.              <li>First link</li>  
  11.              <li>Second link</li>  
  12.          </ul>  
  13. </div>   
  14. </body>  
  15. <script type="text/javascript">  
  16. var app = angular.module('myApp', []);  
  17. app.directive('sidebox', function() {  
  18.     return {  
  19.         restrict: 'EA',  
  20.         scope: {  
  21.             title: '@'  
  22.         },  
  23.         transclude: true,  
  24.         template: '<div class="sidebox">\  
  25.             <div class="content">\  
  26.                 <h2 class="header">{{ title }}</h2>\  
  27.                 <span class="content" ng-transclude>\  
  28.                 </span>\  
  29.             </div>\  
  30.         </div>'  
  31.     };  
  32. });  
  33. </script>  
  34. </html>  

结果:

当  transclude: false,时


如果指令使用了transclude参数,那么在控制器无法正常监听数据模型的变化了。建议在链接函数里使用$watch服务。
9.controller

可以是一个字符串或者函数。

若是为字符串,则将字符串当做是控制器的名字,来查找注册在应用中的控制器的构造函数

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. angular.module('myApp', [])   
  2. .directive('myDirective', function() {   
  3. restrict: 'A', // 始终需要  
  4. controller: 'SomeController'   
  5. })   
  6. // 应用中其他的地方,可以是同一个文件或被index.html包含的另一个文件  
  7. angular.module('myApp')   
  8. .controller('SomeController', function($scope, $element, $attrs, $transclude) {   
  9. // 控制器逻辑放在这里  
  10. });  

也可以直接在指令内部的定义为匿名函数,同样我们可以再这里注入任何服务($log,$timeout等等)

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. angular.module('myApp',[])   
  2. .directive('myDirective', function() {   
  3. restrict: 'A',   
  4. controller:   
  5. function($scope, $element, $attrs, $transclude) {   
  6. // 控制器逻辑放在这里  
  7. }   
  8. });  

另外还有一些特殊的服务(参数)可以注入

(1)$scope,与指令元素相关联的作用域

(2)$element,当前指令对应的 元素

(3)$attrs,由当前元素的属性组成的对象

(4)$transclude,嵌入链接函数,实际被执行用来克隆元素和操作DOM的函数

注意: 除非是用来定义一些可复用的行为,一般不推荐在这使用。

         指令的控制器和link函数(后面会讲)可以进行互换。区别在于,控制器主要是用来提供可在指令间复用的行为但link链接函数只能在当前内部指令中定义行为,且无法再指令间复用。

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!DOCTYPE html>  
  2. <html lang="zh" ng-app="myApp">  
  3. <head>  
  4.     <meta charset="UTF-8">  
  5.     <title>AngularJS入门学习</title>  
  6.     <script type="text/javascript" src="./1.5.3/angular.min.js"></script>  
  7. </head>  
  8.      <hello mycolor ="red">我是林炳文~~~</hello>  
  9. </body>  
  10. <script type="text/javascript">  
  11. var app = angular.module('myApp', []);  
  12. app.directive('hello', function() {  
  13.    return {  
  14.          restrict: 'EA',  
  15.          transclude: true, //注意此处必须设置为true  
  16.          controller:  
  17.          function ($scope, $element,$attrs,$transclude,$log) {  //在这里你可以注入你想注入的服务  
  18.              $transclude(function (clone) {  
  19.                  var a = angular.element('<p>');  
  20.                  a.css('color', $attrs.mycolor);  
  21.                  a.text(clone.text());  
  22.                  $element.append(a);  
  23.              });  
  24.              $log.info("hello everyone");  
  25.          }  
  26.      };  
  27.  });  
  28. </script>  
  29. </html>  

输出结果:


并且在控制台下输出hello everyone

让我们看看$transclude();在这里,它可以接收两个参数,第一个是$scope,作用域,第二个是带有参数clone的回调函数。而这个clone实际上就是嵌入的内容(经过jQuery包装),可以在它上做很多DOM操作。

它还有最简单的用法就是
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <script>  
  2.     angular.module('myApp',[]).directive('mySite', function () {  
  3.      return {  
  4.          restrict: 'EA',  
  5.          transclude: true,  
  6.          controller:  
  7.          function ($scope, $element,$attrs,$transclude,$log) {  
  8.              var a = $transclude(); //$transclude()就是嵌入的内容  
  9.              $element.append(a);  
  10.          }  
  11.      };  
  12.  });  
  13.  </script>  
注意:使用$transclude会生成一个新的作用域。

默认情况下,如果我们简单实用$transclude(),那么默认的其作用域就是$transclude生成的作用域

但是如果我们实用$transclude($scope,function(clone){}),那么作用域就是directive的作用域了

那么问题又来了。如果我们想实用父作用域呢

可以使用$scope.$parent

同理想要一个新的作用域也可以使用$scope.$parent.new();
10.controllerAs

这个选项的作用是可以设置你的控制器的别名

一般以前我们经常用这样方式来写代码:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. angular.module("app",[])  
  2.   .controller("demoController",["$scope",function($scope){  
  3.     $scope.title = "angualr";  
  4.   }])  
  5.   
  6.  <div ng-app="app" ng-controller="demoController">  
  7.       {{title}}  
  8. </div>  

后来angularjs1.2给我们带来新语法糖,所以我们可以这样写

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. angular.module("app",[])  
  2.   .controller("demoController",[function(){  
  3.     this.title = "angualr";  
  4.   }])  
  5.   
  6.   <div ng-app="app" ng-controller="demoController as demo">  
  7.        {{demo.title}}  
  8.   </div>  

同样的我们也可以再指令里面也这样写

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <script>  
  2.     angular.module('myApp',[]).directive('mySite', function () {  
  3.      return {  
  4.          restrict: 'EA',  
  5.          transclude: true,  
  6.          controller:'someController',  
  7.          controllerAs:'mainController'  
  8.          //..其他配置  
  9.      };  
  10.  });  
  11.  </script>  

11.require(字符串或者数组)

字符串代表另一个指令的名字,它将会作为link函数的第四个参数。具体用法我们可以举个例子说明。假设现在我们要编写两个指令,两个指令中的link链接函数中(link函数后面会讲)存在有很多重合的方法,这时候我们就可以将这些重复的方法写在第三个指令的controller中(上面也讲到controller经常用来提供指令间的复用行为)然后在这两个指令中,require这个拥有controller字段的的指令(第三个指令),

最后通过link链接函数的第四个参数就可以引用这些重合的方法了。

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. <!doctype html>  
  2. <html ng-app="myApp">  
  3. <head>  
  4.   <script src="http://cdn.staticfile.org/angular.js/1.2.10/angular.min.js"></script>  
  5. </head>  
  6. <body>  
  7.   
  8.              
  9.   <outer-directive>  
  10.      <inner-directive></inner-directive>  
  11.      <inner-directive2></inner-directive2>  
  12.   </outer-directive>  
  13.   <script>  
  14.     var app = angular.module('myApp', []);  
  15.     app.directive('outerDirective', function() {  
  16.           return {  
  17.                scope: {},  
  18.                restrict: 'AE',  
  19.                controller: function($scope) {        
  20.                   this.say = function(someDirective) {   
  21.                      console.log('Got:' + someDirective.message);  
  22.                   };  
  23.                }  
  24.            };  
  25.     });  
  26.     app.directive('innerDirective', function() {  
  27.           return {  
  28.                scope: {},  
  29.                restrict: 'AE',  
  30.                require: '^outerDirective',  
  31.                link: function(scope, elem, attrs, controllerInstance) {  
  32.                        scope.message = "Hi,leifeng";  
  33.                        controllerInstance.say(scope);  
  34.                }  
  35.           };  
  36.     });  
  37.     app.directive('innerDirective2', function() {  
  38.           return {  
  39.                scope: {},  
  40.                restrict: 'AE',  
  41.                require: '^outerDirective',  
  42.                link: function(scope, elem, attrs, controllerInstance) {  
  43.                        scope.message = "Hi,shushu";  
  44.                        controllerInstance.say(scope);  
  45.                }  
  46.           };  
  47.     });  
  48.       
  49.       
  50.   </script>  
  51.   
  52. </body>  
  53. </html>  

上面例子中的指令innerDirective和指令innerDirective2复用了定义在指令outerDirective的controller中的方法

也进一步说明了,指令中的controller是用来让不同指令间通信用的。

另外我们可以在require的参数值加上下面的某个前缀,这会改变查找控制器的行为:

(1)没有前缀,指令会在自身提供的控制器中进行查找,如果找不到任何控制器,则会抛出一个error

(2)?如果在当前的指令没有找到所需的控制器,则会将null传给link连接函数的第四个参数

(3)^如果在当前的指令没有找到所需的控制器,则会查找父元素的控制器

(4)?^组合

12.Anguar的指令编译过程

首先加载AngularJS库,查找到ng-app指令,从而找到应用的边界,

根据ng-app划定的作用域来调用$compile服务进行编译,angularjs会遍历整个HTML文档,并根据js中指令的定义来处理在页面上声明的各个指令按照指令的优先级(priority)排列,根据指令中的配置参数(template,place,transclude等)转换DOM然后就开始按顺序执行各指令的compile函数(如果指令上有定义compile函数)对模板自身进行转换

注意:此处的compile函数是我们指令中配置的,跟上面说的$compile服务不一样。每个compile函数执行完后都会返回一个link函数,所有的link函数会合成一个大的link函数

然后这个大的link函数就会被执行,主要做数据绑定,通过在DOM上注册监听器来动态修改scope中的数据,或者是使用$watchs监听 scope中的变量来修改DOM,从而建立双向绑定等等。若我们的指令中没有配置compile函数,那我们配置的link函数就会运行,她做的事情大致跟上面complie返回之后所有的link函数合成的的大的link函数差不多。

所以:在指令中compile与link选项是互斥的,如果同时设置了这两个选项,那么就会把compile所返回的函数当做是链接函数,而link选项本身就会被忽略掉

13、编译函数 Compile function

function compile(tElement, tAttrs, transclude) { ... }
编译函数是用来处理需要修改模板DOM的情况的。因为大部分指令都不需要修改模板,所以这个函数也不常用。需要用到的例子有ngTrepeat,这个是需要修改模板的,还有ngView这个是需要异步载入内容的。编译函数接受以下参数。

tElement - template element - 指令所在的元素。对这个元素及其子元素进行变形之类的操作是安全的。
tAttrs - template attributes - 这个元素上所有指令声明的属性,这些属性都是在编译函数里共享的。
transclude - 一个嵌入的链接函数function(scope, cloneLinkingFn)。
注意:在编译函数里面不要进行任何DOM变形之外的操作。 更重要的,DOM监听事件的注册应该在链接函数中做,而不是编译函数中。
编译函数可以返回一个对象或者函数。
返回函数 - 等效于在编译函数不存在时,使用配置对象的link属性注册的链接函数。
返回对象 - 返回一个通过pre或post属性注册了函数的对象。参考下面pre-linking和post-liking函数的解释。

14、链接函数 Linking function

function link(scope, iElement, iAttrs, controller) { ... }
链接函数负责注册DOM事件和更新DOM。它是在模板被克隆之后执行的,它也是大部分指令逻辑代码编写的地方。
scope - 指令需要监听的作用域。
iElement - instance element - 指令所在的元素。只有在postLink函数中对元素的子元素进行操作才是安全的,因为那时它们才已经全部链接好。
iAttrs - instance attributes - 实例属性,一个标准化的、所有声明在当前元素上的属性列表,这些属性在所有链接函数间是共享的。
controller - 控制器实例,也就是当前指令通过require请求的指令direct2内部的controller。比如:direct2指令中的controller:function(){this.addStrength = function(){}},那么,在当前指令的link函数中,你就可以通过controller.addStrength进行调用了。
Pre-linking function 在子元素被链接前执行。不能用来进行DOM的变形,以防链接函数找不到正确的元素来链接。
Post-linking function 所有元素都被链接后执行。

说明:

    compile选项本身并不会被频繁使用,但是link函数则会被经常使用。本质上,当我们设置了link选项,实际上是创建了一个postLink() 链接函数,以便compile() 函数可以定义链接函数。通常情况下,如果设置了compile函数,说明我们希望在指令和实时数据被放到DOM中之前进行DOM操作,在这个函数中进行诸如添加和删除节点等DOM操作是安全的。compile和link选项是互斥的。如果同时设置了这两个选项,那么会把compile所返回的函数当作链接函数,而link选项本身则会被忽略。译函数负责对模板DOM进行转换。链接函数负责将作用域和DOM进行链接。 在作用域同DOM链接之前可以手动操作DOM。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。 链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值