zoukankan      html  css  js  c++  java
  • angularjs directive 指令使用

    directive指令:

    var myModule = angular.module(...); 

         myModule.directive('directiveName', function factory(injectables) { 

         var directiveDefinitionObject = { 

       priority: 0,  /***priority(数字),可选参数,指明指令的优先级,若在单个DOM上有多个指令,则优先级高的先执行;****/

       template: '<div></div>',  /**1.(字符串或者函数)可选参数,可以是:html

                       2. 一个函数,可接受两个参数tElementtAttrs; 其中tElement是指使用此指令的元素,而tAttrs则实例的属性,它是一个由元素上所有的属性组成的集合(对象)形如:

                       <hello-world2 title = '我是第二个directive'></hello-world2> template: function(tElement,tAttrs){}**/ 

       templateUrl: 'directive.html', /**可选参数,可以是(1)一个代表HTML文件路径的字符串(2)一个函数,可接受两个参数tElement和tAttrs(大致同上)**/

       replace: false,  /***replace (布尔值),默认值为false,设置为true时候; replace为true时,hello-world这个标签不在了,反之,则存在。***/

       transclude: false, /***如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",

                    这时,指令内部的内容会嵌入到ng-transclude这个div中。这个配置选项可以让我们提取包含在指令那个元素里面的内容,再将它放置在指令模板的特定位置。

                    当你开启transclude后,你就可以使用ng-transclude来指明了应该在什么地方放置transcluded内容;

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

       restrict: 'A',     /***restrict(字符串)可选参数,指明指令在DOM里面以什么形式被声明;取值有:E(元素),A(属性),C(类),M(注释),其中默认值为A;当然也可以两个一起用,比如EA.表示即可以是元素也可以是属性。

                                        E(元素):<directiveName></directiveName>

                                            A(属性):<div directiveName='expression'></div>

                                        C(类): <div class='directiveName'></div>

                                            M(注释):<--directive:directiveName expression-->

                  一般情况下E/A/C用得比较多。 **/ 

       scope: false,  /***(1)默认值false。表示继承父作用域; 

                 (2)true。表示继承父作用域,并创建自己的作用域(子作用域); 

                 (3){}。表示创建一个全新的隔离作用域;当你想要创建一个可重用的组件时隔离作用域是一个很好的选择; 隔离作用域可以通过绑定策略来访问父作用域的属性。 

                    directive 在使用隔离 scope 的时候,提供了三种方法同隔离之外的地方交互。这三种分别是:

                    @ 绑定一个局部 scope 属性到当前 dom 节点的属性值。结果总是一个字符串,因为 dom 属性是字符串。单向, 父变化==》 子变化

                    & 提供一种方式执行一个表达式在父 scope 的上下文中。如果没有指定 attr 名称,则属性名称为相同的本地名称。

                    = 通过 directive 的 attr 属性的值在局部 scope 的属性和父 scope 属性名之间建立双向绑定。双向****/ 

       compile: function compile(tElement, tAttrs, transclude) {

         return {

           pre: function preLink(scope, iElement, iAttrs, controller) { ... },

           post: function postLink(scope, iElement, iAttrs, controller) { ... }

        }

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

             },

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

           // 控制器逻辑放在这里

            }

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

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

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

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

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

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

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

    控制器主要是用来提供可在指令间复用的行为但link链接函数只能在当前内部指令中定义行为,且无法再指令间复用。 

    指令中的controller是用来让不同指令间通信用的。

    **/

            controllerAs:'mainController',    /***这个选项的作用是可以设置你的控制器的别名***/ 

            require:'',   /*** require(字符串或者数组)

    字符串代表另一个指令的名字,它将会作为link函数的第四个参数。具体用法我们可以举个例子说明。假设现在我们要编写两个指令,两个指令中的link链接函数中(link函数后面会讲)存在有很多重合的方法,

    这时候我们就可以将这些重复的方法写在第三个指令的controller中(上面也讲到controller经常用来提供指令间的复用行为)然后在这两个指令中,require这个拥有controller字段的的指令(第三个指令),

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

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

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

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

    (4)?^组合***/

            link: function postLink(scope, iElement, iAttrs) { ... }

    /***link函数就会被执行,主要做数据绑定,通过在DOM上注册监听器来动态修改scope中的数据,或者是使用$watchs监听 scope中的变量来修改DOM,从而建立双向绑定等等。若我们的指令中没有配置compile函数,那我们配置的link函数就会运行

     在指令中compile与link选项是互斥的,如果同时设置了这两个选项,那么就会把compile所返回的函数当做是链接函数,而link选项本身就会被忽略掉链接函数负责注册DOM事件和更新DOM。它是在模板被克隆之后执行的,它也是大部分指令逻辑代码编写的地方。

     scope - 指令需要监听的作用域。

     iElement - instance element - 指令所在的元素。只有在postLink函数中对元素的子元素进行操作才是安全的,因为那时它们才已经全部链接好。

     iAttrs - instance attributes - 实例属性,一个标准化的、所有声明在当前元素上的属性列表,这些属性在所有链接函数间是共享的。

     controller - 控制器实例,也就是当前指令通过require请求的指令direct2内部的controller。

     ***/

    }; 

     return directiveDefinitionObject; 

    })

     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选项本身就会被忽略掉

     编译函数 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函数的解释。

     链接函数 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。在实践中,编写自定义指令时这种操作是非常罕见的,但有几个内置指令提供了这样的功能。

    链接函数是可选的。如果定义了编译函数,它会返回链接函数,因此当两个函数都定义时,编译函数会重载链接函数。

    如果我们的指令很简单,并且不需要额外的设置,可以从工厂函数(回调函数)返回一个函数来代替对象。如果这样做了,这个函数就是链接函数。

  • 相关阅读:
    背包问题
    计蒜客lev3
    线段树BIT操作总结
    图论题收集
    Codeforces Round #607 (Div. 2) 训练总结及A-F题解
    2-sat 学习笔记
    洛谷 P3338 【ZJOI2014】力/BZOJ 3527 力 题解
    $noi.ac$ #51 array 题解
    洛谷 P3292 【SCOI2016】幸运数字/BZOJ 4568 幸运数字 题解
    洛谷 P5283 【十二省联考2019】异或粽子 题解
  • 原文地址:https://www.cnblogs.com/sxhlf/p/13941875.html
Copyright © 2011-2022 走看看