angular之directive小结


关于 restrict属性

对于angular 指令的理解:html

    好比你想建立一个指令 想被调用的人经过
jquery

<my-directive></my-direvtive>

的话,对于属性就能够设置为 restrict    :   E(元素)express

    若是是
数组

<div my-directive> </div>

restrict    :   A(属性,默认值)app

    若是是:
dom

<div class=“directive:expression;”> </div>

restrict    :   C(类名)函数

<-- directive:my-directive expression -->

restrict    :   M(注释)post

能够混用,也能够单独使用。性能

对于scope属性

@  @attr     本地做用域属性
=  =attr     双向属性
&  &attr     父级做用域绑定

ps:ui

对于 & 父级做用域: 传递进来的参数必须是父级的函数方法,  而后在指令中,经过 test() 获取到 传递进来的函数,这个还不够,还必须再执行一次 test()() 才是真正的执行这个方法。

或者在指令的调用上面,直接写好test(t),而后在指令中调用的时候 ,$scope.test({t:'fda'}) 就能够了。


对于 @ 本地做用域: 只能传递字符串进来,对于方法或者对象是传递不进来的

对于 = 双向属性: 能够传递对象进来,也能够是字符串,可是不能传递方法。  同时能够在 指令中修改这个对象,父级里面的这个对象也会跟着修改的。



controller,link,compile有什么不一样

//directives.js增长exampleDirective
phonecatDirectives.directive('exampleDirective', function() {
    return {
        restrict: 'E',
        template: '<p>Hello {{number}}!</p>',
        controller: function($scope, $element){
            $scope.number = $scope.number + "22222 ";
        },
        link: function(scope, el, attr) {
            scope.number = scope.number + "33333 ";
        },
        compile: function(element, attributes) {
            return {
                pre: function preLink(scope, element, attributes) {
                    scope.number = scope.number + "44444 ";
                },
                post: function postLink(scope, element, attributes) {
                    scope.number = scope.number + "55555 ";
                }
            };
        }
    }
});

//controller.js添加
dtControllers.controller('directive2',['$scope',
    function($scope) {
        $scope.number = '1111 ';
    }
]);

//html
<body ng-app="phonecatApp">
    <div ng-controller="directive2">
        <example-directive></example-directive>
    </div>
</body>

// 运行结果。
Hello 1111 22222 44444 55555 !

由结果能够看出来,controller先运行,compile后运行,link不运行。

将上例中的compile注释掉

//        compile: function(element, attributes) {
//            return {
//                pre: function preLink(scope, element, attributes) {
//                    scope.number = scope.number + "44444 ";
//                },
//                post: function postLink(scope, element, attributes) {
//                    scope.number = scope.number + "55555 ";
//                }
//            };
//        }

// 结果。
Hello 1111 22222 33333 !
由结果能够看出来,controller先运行,link后运行,link和compile不兼容。

对于 compile (编译)   link(连接),先编译,后链接,可是有了编译以后,对于连接就起不到到做用了。

在compile 阶段主要是实现:标签的解析和替换。 在编译阶段是获取不到 scope 的。主要参数(element.attrbutes)

在link 阶段主要是实现:数据绑定等操做。在link阶段是能够获取到scope 的 主要参数是(scope,element,attrs);

link 与controller 的区别

对于一个指令,若是你想将当前指令的API暴露给其余指令使用的时候,可使用controller,不然建议使用link。


对于require参数的理解

参数:字符串或者数组

? 若是在当前指令中没有找到所需的控制器,就会将null传递给link函数中的第四个参数

^ 若是添加了这个前缀,指令会在上游的指令链中查找require参数所指定的控制器

?^ 合并了前面两个说法

没有前缀  指令就会自身提供的控制器中查找,若是没有查找到,就会抛出异常来。

对于compile函数

返回一个对象或者函数。

与link 是互斥的,优先级高于 link 。

能够理解成:compile函数在link函数被执行以前用来作一些DOM改造的。

若是有了compile函数,就不能有link 函数了,link函数是由compile函数返回的。


要注意的是 compile 是不能访问scope的,而且返回一link函数。

compile:function(tElem,attrs){
    // tElem:指令所在的元素
    // attrs: 元素上赋予的参数的标准化列表    
    
    // 在这边能够作一些对于dom元素的操做

    return function(scope,elem,attrs){
    
    }
}

因此,大多数状况下,你只须要link 函数,由于大部分的指令只须要考虑注册事件的监听,监听模型,以及更新DOM等,这些都是能够在link函数中完成的,可是对于像ng-repeat之类的指令,须要克隆和重复dom元素屡次,在link函数执行以前由compile函数来完成。

对于link 与scope

指令生成出的模板其实没有太多的意义,除非他在特定的scope下编译,默认状况下,指令并不会建立新的子scope

,更多的,他是使用父scope,也就是说,若是指令存在于一个controller下,他就会使用controller的scope,如何运行

scope,咱们须要用到一个link函数,他由指令定义对象中的link属性配置。

link:function(scope,elem,attrs){
    // scope:父亲controller的scope
    // elem:jqLite(jquery的子集)包装的dom元素,不须要再使用$()包装了。
    // attrs:一个包含了指令所在元素的属性的标准化的参数对象,
    // 例子:好比你在html中添加一些属性,那么能够在link函数中经过attrs.someAttribute来使用他。
}


因此说:link 函数主要是为dom 元素添加事件监听,监听模型属性变化,以及更新dom。


另外 若是 有参数 require 的话,对于link 函数方面就会多一个参数 controller 

{
require:'?ngModal',
link:function(scope,element,attrs,ctrl){
    // 这里 ctrl 就是  require 进来的ctrl
}
}

若是require的参数是数组的话。

{
require:['?ngModal','?test'],
link:function(scope,element,attrs,ctrls){
    // 这里 ctrl 就是  require 进来的ctrl
    var modalCtrl = ctrls[0];
    var testCtrl = ctrls[1];
}
}



指令是如何被编译出来的

    在应用引导启动的时候,ng开始使用$compile服务遍历dom元素,这个服务基于注册过的指令在标记文本中搜索指令,一旦全部的指令被识别后,ng执行他们的compile方法,正如前面所讲的,compile 方法返回一个link函数,被添加到稍后执行的link函数列表中,这个阶段被称为编译阶段。若是指令须要被克隆屡次,好比ng-repeat,compile函数只会在编译阶段被执行一次,复制这些模板,可是link函数会针对于每一个被复制的实例被执行。因此分开来处理,让咱们在性能方面有必定的提高。

    这也说明了为何在compile函数中不能访问scope对象。在编译阶段之后,就开始了连接阶段,在这个阶段,全部的link函数被一一执行。指令创造出来的模板会在正确的scope下被解析和处理。而后返回具备事件响应的真实的dom节点。


关于改变指令的scope

默认状况下,指令获取他的父节点的controller的scope,但这并不适用全部状况。若是将父controller的scope暴露给指令,那么他们能够随意修改scope的属性,在某些状况下,你的指令但愿可以添加一些仅限内部使用的属性和方法,若是咱们在父的scope中添加,会污染父scope,其实咱们还能够有两个选择。

  1. 一个子scope,这个scope原型继承于父scope

  2. 一个隔离的scope,一个孤立存在不继承父scope的scope

这样的scope能够经过指令对象中的scope属性老配置

scope:true  // 建立了一个继承父scope的新的子
scope:{}  // 建立了一个隔离的scope,隔离的scope在咱们想建立可重用的指令的时候是很是有好处的。
经过使用隔离的scope,咱们可以保证咱们的指令是自包含的,能够被很容易的插入到HTML中,他内部不能访问父的scope,因此保证了父scope不被污染。


transclude:'element' 和  transclude:true 的区别

有时候咱们要嵌入指令元素自己,而不只仅是他的内容,这种状况下,咱们须要使用transclude:"element",和transclude:true不一样,他讲标记了ng-transclude指令的元素一块儿包含到了指令模板中,使用transclusion, 你的link函数会获取到一个叫transclude的连接函数,这个函数绑定了正确的指令scope,而且传入了另一个拥有被嵌入dom元素拷贝的函数,你能够在这个transclude函数中执行好比修改元素拷贝或者将他添加到dom上等操。


controller函数与require

若是你须要容许其余指令和你的指令发生交互的话,你须要使用controller函数,好比有些状况下,你须要经过组合两个指令来实现一个ui组件,那么你能够经过以下使用

app.directive('outerDirective', function() {
  return {
    scope: {},
    restrict: 'AE',
    controller: function($scope, $compile, $http) {
      // $scope is the appropriate scope for the directive
      this.addChild = function(nestedDirective) { // this refers to the controller
        console.log('Got the message from nested directive:' + nestedDirective.message);
      };
    }
  };
});


当另一个指令须要使用到这个controller的时候

app.directive('innerDirective', function() {
  return {
    scope: {},
    restrict: 'AE',
    require: '^outerDirective',   //  require controller 方法
    
    // link 参数中就会多一个参数 就是那个require 进来的controller
    link: function(scope, elem, attrs, controllerInstance) {
      //the fourth argument is the controller instance you require
      scope.message = "Hi, Parent directive";
      controllerInstance.addChild(scope);
    }
  };
});


关于replace参数

若是设置  repace : true 的话,就会隐藏掉 对于 指令命名的html 标签

相似 <hello> </hello>  若是replace 设置为true的话,就会消失不显示。

关于transclude参数

若是设置了transclude 为true的话,就会把本来指令标签中用于写的东西放置到   ng-transclude 中去。

<div ng-transclude> 方式获取到的内容</div>

若是设置了transclude 为true的话,除了可使用ng-transclude 指令, 若是你还须要对本来的内容进行替换的话

能够在link 或者controller里面添加一个参数$transclude 

link:function($scope,$element,$attrs,controller,$transclude){
    // clone 参数就是用户输入进去的内容。
    $transclude(function(clone){
        // 进行其余操做。
    });
}

案例

// html
<div my-link value=" target="_blank">百度</div>

// js

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

app.directive('myLink',function(){
    return {
        restrict:'EA',
        transclude:true,
        controller:function($scope,$element,$attrs,$transclude){
            $transclude(function(clone){
                var a  = angular.element('<a>');
                a.attr('href',$attrs.value);
                a.attr('target',$attrs.target);
                a.text(clone.text());
                $element.append(a);
            })
        }
    
    }
})


关于 require 参数

对于前缀 ?  ^     ?^   空

若是为空的话,表示在当前指令中查找

若是为?的话,表示没有查找到的话,就会以null做为link 函数的第四个参数

若是为^ 的话,表示能够指向上游查找指令。

关于require 引入多个指令,对link 方法的影响

若是

require:['?^add','?^minor']

的话,

会致使 link 方法影响

link:function(scope,element,attrs,resultCtrl){
    // add : resultCtrl[0];
    // minor: resultCtrl[1];
}

若是想调用指令的方法,须要在对应指令中的controller 中定义方法

app.directive('add',function(){
    return {
        controller:function(){
            this.add = function(){
            
            }
        }
    }
})

则调用的时候就须要

resultCtrl[0].add() 就能够调用了。

关于如何同时使用compile 和link 的方法

因为 compile 和link 共同存在的话,只会触发compile 方法。而link 方法是不被触发执行的。

而能够经过这种方式:

{
 restrict:'EA',
 compile:function(element,attrs){
     // 编译期间作的事情。
     
     return function link(scope,element,attrs,controller){
         // link  函数作的事情。
     }
     
 }

}
相关文章
相关标签/搜索