您的位置:首页 > Web前端 > AngularJS

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

2017-02-07 16:24 375 查看
此文接 跟我学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

 





<!DOCTYPE html>  

<html lang="zh" ng-app="myApp">  

<head>  

    <meta charset="UTF-8">  

    <title>AngularJS入门学习</title>  

    <script type="text/javascript" src="./1.5.3/angular.min.js"></script>  

</head>  

<div sidebox title="Links">  

         <ul>  

             <li>First link</li>  

             <li>Second link</li>  

         </ul>  

</div>   

</body>  

<script type="text/javascript">  

var app = angular.module('myApp', []);  

app.directive('sidebox', function() {  

    return {  

        restrict: 'EA',  

        scope: {  

            title: '@'  

        },  

        transclude: true,  

        template: '<div class="sidebox">\  

            <div class="content">\  

                <h2 class="header">{{ title }}</h2>\  

                <span class="content" ng-transclude>\  

                </span>\  

            </div>\  

        </div>'  

    };  

});  

</script>  

</html>  

结果:



当  transclude: false,时



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

9.controller

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

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

[html] view
plain copy

 





angular.module('myApp', [])   

.directive('myDirective', function() {   

restrict: 'A', // 始终需要  

controller: 'SomeController'   

})   

// 应用中其他的地方,可以是同一个文件或被index.html包含的另一个文件  

angular.module('myApp')   

.controller('SomeController', function($scope, $element, $attrs, $transclude) {   

// 控制器逻辑放在这里  

});  

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

[html] view
plain copy

 





angular.module('myApp',[])   

.directive('myDirective', function() {   

restrict: 'A',   

controller:   

function($scope, $element, $attrs, $transclude) {   

// 控制器逻辑放在这里  

}   

});  

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

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

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

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

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

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

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

[html] view
plain copy

 





<!DOCTYPE html>  

<html lang="zh" ng-app="myApp">  

<head>  

    <meta charset="UTF-8">  

    <title>AngularJS入门学习</title>  

    <script type="text/javascript" src="./1.5.3/angular.min.js"></script>  

</head>  

     <hello mycolor ="red">我是林炳文~~~</hello>  

</body>  

<script type="text/javascript">  

var app = angular.module('myApp', []);  

app.directive('hello', function() {  

   return {  

         restrict: 'EA',  

         transclude: true, //注意此处必须设置为true  

         controller:  

         function ($scope, $element,$attrs,$transclude,$log) {  //在这里你可以注入你想注入的服务  

             $transclude(function (clone) {  

                 var a = angular.element('<p>');  

                 a.css('color', $attrs.mycolor);  

                 a.text(clone.text());  

                 $element.append(a);  

             });  

             $log.info("hello everyone");  

         }  

     };  

 });  

</script>  

</html>  

输出结果:



并且在控制台下输出hello everyone

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

它还有最简单的用法就是

[html] view
plain copy

 





<script>  

    angular.module('myApp',[]).directive('mySite', function () {  

     return {  

         restrict: 'EA',  

         transclude: true,  

         controller:  

         function ($scope, $element,$attrs,$transclude,$log) {  

             var a = $transclude(); //$transclude()就是嵌入的内容  

             $element.append(a);  

         }  

     };  

 });  

 </script>  

注意:使用$transclude会生成一个新的作用域。

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

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

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

可以使用$scope.$parent

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

10.controllerAs

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

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

[html] view
plain copy

 





angular.module("app",[])  

  .controller("demoController",["$scope",function($scope){  

    $scope.title = "angualr";  

  }])  

  

 <div ng-app="app" ng-controller="demoController">  

      {{title}}  

</div>  

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

[html] view
plain copy

 





angular.module("app",[])  

  .controller("demoController",[function(){  

    this.title = "angualr";  

  }])  

  

  <div ng-app="app" ng-controller="demoController as demo">  

       {{demo.title}}  

  </div>  

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

[html] view
plain copy

 





<script>  

    angular.module('myApp',[]).directive('mySite', function () {  

     return {  

         restrict: 'EA',  

         transclude: true,  

         controller:'someController',  

         controllerAs:'mainController'  

         //..其他配置  

     };  

 });  

 </script>  

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

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

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

[html] view
plain copy

 





<!doctype html>  

<html ng-app="myApp">  

<head>  

  <script src="http://cdn.staticfile.org/angular.js/1.2.10/angular.min.js"></script>  

</head>  

<body>  

  

             

  <outer-directive>  

     <inner-directive></inner-directive>  

     <inner-directive2></inner-directive2>  

  </outer-directive>  

  <script>  

    var app = angular.module('myApp', []);  

    app.directive('outerDirective', function() {  

          return {  

               scope: {},  

               restrict: 'AE',  

               controller: function($scope) {        

                  this.say = function(someDirective) {   

                     console.log('Got:' + someDirective.message);  

                  };  

               }  

           };  

    });  

    app.directive('innerDirective', function() {  

          return {  

               scope: {},  

               restrict: 'AE',  

               require: '^outerDirective',  

               link: function(scope, elem, attrs, controllerInstance) {  

                       scope.message = "Hi,leifeng";  

                       controllerInstance.say(scope);  

               }  

          };  

    });  

    app.directive('innerDirective2', function() {  

          return {  

               scope: {},  

               restrict: 'AE',  

               require: '^outerDirective',  

               link: function(scope, elem, attrs, controllerInstance) {  

                       scope.message = "Hi,shushu";  

                       controllerInstance.say(scope);  

               }  

          };  

    });  

      

      

  </script>  

  

</body>  

</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。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。 链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: