angularjs指令详细分析&&与控制器数据交互

简介(转)

指令作为AngularJS中最为重要的部分,所以这个框架本身也是自带了比较多的的指令,但是在开发中,这些指令通常不能满足我们的需要,所以我们也是需要自定义一些指令的。指令是我们用来扩展浏览器能力的技术之一。在DOM编译期间,和HTML元素关联着的指令会被检测到,并且被执行。这使得指令可以为DOM指定行为,或者改变它。

angular在编译期间,编译器会用$interpolate服务去检查文本中是否嵌入了表达式。这个表达式会被当成一个监视器一样注册,并且作为$digest循环中的一部分,它会自动更新。
  

HTML的编译分为三个阶段:

  • 首先浏览器会用它的标准API将HTML解析成DOM。 你需要认清这一点,因为我们的模板必须是可被解析的HTML。这是AngularJS和那些“以字符串为基础而非以DOM元素为基础的”模板系统的区别之处。

  • DOM的编译是由 $compile 方法来执行的。 这个方法会遍历DOM并找到匹配的指令。一旦找到一个,它就会被加入一个指令列表中,这个列表是用来记录所有和当前DOM相关的指令的。 一旦所有的指令都被确定了,会按照优先级被排序,并且他们的 compile 方法会被调用。 指令的 $compile() 函数能修改DOM结构,并且要负责生成一个link函数(后面会提到)。$compile方法最后返回一个合并起来的链接函数,这时链接函数是每一个指令的compile函数返回的链接函数的集合。

  • 通过调用上一步所说的链接函数来将模板与作用域链接起来。这会轮流调用每一个指令的链接函数,让每一个指令都能对DOM注册监听事件,和建立对作用域的的监听。这样最后就形成了作用域的DOM的动态绑定。任何一个作用域的改变都会在DOM上体现出来。

模板代码

var myModule = angular.module(...);
myModule.directive('directiveName',[function(){
    var directiveDefinitionObject = {
        priority: 0,
        template: '<div></div>',
        templateUrl: 'directive.html',
        replace: false,
        transclude: false,
        restrict: 'A',
        scope: false,
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                pre: function preLink(scope, iElement, iAttrs, controller) { ... },
                post: function postLink(scope, iElement, iAttrs, controller) { ... }
            }
        },
        link: function postLink(scope, iElement, iAttrs) { ... }
   };
   return directiveDefinitionObject;
}]);

指令对象的属性详解(转)

  1. name:当前作用域的名称
  2. priority:当一个DOM上有多个指令时,就会需要指定指令执行的顺序。 这个优先级就是用来在执行指令的compile函数前,先排序的。高优先级的先执行。
  3. terminal:该参数用来定义是否停止当前元素上比本指令优先级低的指令,如果值为true,就是正常情况,按照优先级高低的顺序来执行,如果设置为false,就不会执行当前元素上比本指令优先级低的指令。
  4. scope:

    • 如果定义为true,那么当前指令汇创建一个新的作用域。这一创建新作用域的规则不适用于模板的根节点,因为模板的根节点总是会得到一个新的作用域。

    • {},对象哈希 - 那么一个新的“孤立的”作用域就会被创建。这个“孤立的”作用域区别于一般作用域的地方在于,它不会以原型继承的方式直接继承自父作用域。这对于创建可重用的组件是非常有用的,因为可重用的组件一般不应该读或写父作用域的数据。 这个“孤立的”作用域使用一个对象哈希来表示,这个哈希定义了一系列本地作用域属性,这些属性的值可以有以下几种方式。

      • @ 或 @attr - 将本地作用域成员和DOM属性绑定。使用@实现单向绑定。
      • = 或 =expression - 在本地作用域属性和父作用域属性间建立一个双向的绑定。使用=实现双向绑定
      • & 或 &attr - 调用父scope里的方法。
  5. controller:这个是指令内部的controller,跟angular中的controller不一样。它的作用是暴露此指令的一些方法给其他指令使用。这个控制器函数是在预编译阶段被执行的,并且它是共享的,这就使得指令间可以互相交流来扩大自己的能力。

  6. require:请求将另一个指令,假设为direct2,中的内部controller作为参数传入到当前指令的链接函数link中,这样在当前指令的link函数中,就可以调用direct2指令中的内部controller中定义的方法了。 这个请求需要传递被请求指令的名字。如果没有找到,就会触发一个错误。请求的名字可以加上下面两个前缀:

    • ? - 不要触发错误,这只是一个可选的请求。
    • ^ - 没找到的话,在父元素的作用域里面去查找有没有。
  7. restrict:EACM中的任意一个字母。它是用来限制指令的声明格式的。如果没有这一项。那就只允许使用属性形式的指令。

    • E - 元素名称:
    • A - 属性:
    • C - 类名:
    • M - 注释:
  8. template:将当前的元素替换掉。 这个替换过程会自动将元素的属性和css类名添加到新元素上。

  9. templateUrl:和template属性一样,只不过这里指示的是一个模板的URL。因为模板加载是异步的,所有编译和链接都会等到加载完成后再执行。
  10. replace:如果被设置成true,那么页面上指令内部里面的内容会被模板替换。比如:
    这是指令内部的内容
    ,hello指令内部的div内容将会被模板替换掉。
  11. transclude:如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:”
    hello every
    ”,这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了
    hello every
    这是指令内部的内容
  12. compile: function compile(tElement, tAttrs, transclude) { … }
    编译函数是用来处理需要修改模板DOM的情况的。因为大部分指令都不需要修改模板,所以这个函数也不常用。需要用到的例子有 ngTrepeat ,这个是需要修改模板的,还有 ngView 这个是需要异步载入内容的。编译函数接受以下参数。

    • tElement - template element - 指令所在的元素。对这个元素及其子元素进行变形之类的操作是安全的。
    • tAttrs - template attributes - 这个元素上所有指令声明的属性,这些属性都是在编译函数里共享的。
    • transclude - 一个嵌入的链接函数 function(scope, cloneLinkingFn) 。

    注意:在编译函数里面不要进行任何DOM变形之外的操作。 更重要的,DOM监听事件的注册应该在链接函数中做,而不是编译函数中。

    编译函数可以返回一个对象或者函数。

    • 返回函数 - 等效于在编译函数不存在时,使用配置对象的 link 属性注册的链接函数。

    • 返回对象 - 返回一个通过 pre 或 post 属性注册了函数的对象。

  13. link:unction 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 所有元素都被链接后执行。

      当我们的angular应用引导启动的时候,angular将会使用$compile服务遍历DOM元素,在所有的指令都被识别之后,将会调用指令的compile方法,返回一个link函数,然后将这个link函数添加到稍后执行的 link 函数列表中,这个过程被称为编译阶段。像ng-repeat这样的指令,需要被重复克隆很多次,compile函数只在编译阶段被执行一次,并且复制这些模板,但是link 函数会针对每个被复制的实例被执行。所以分开处理,让我们在性能上有一定的提高。
      

控制器数据与指令交互demo

指令的作用域可以获取到控制器中的数据,也可以实时修改控制器中的数据

指令

angularApp.directive('test',[function() {
    return {
        restrict: 'EA',
        replace: true,
        template: '<div><h1>计算结果{{sum}}</h1><div class="btn btn-default" ng-click="aaa()">test</div></div>',
        scope: {
            conf: '='   //在本地作用域属性和父作用域属性间建立一个双向的绑定
        },
        link: function(scope, element, attrs) {
            var conf = scope.conf;
            scope.sum = conf.a + conf.b;
            scope.aaa = function () {
                // scope.$parent.data.sum = scope.sum;
                scope.conf.sum = scope.sum;
            }
        }
    }

}]);

控制器及页面

$scope.data = {
    a:2,
    b:5,
    sum:1
}
<test conf="data"></test>
<h1>{{data.sum}}</h1>
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leason00

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值