AngularJS指令的详解

时间:2022-09-07 20:51:09

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

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

  HTML的编译分为三个阶段:

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

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

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

  指令的模板代码:

 var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
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;
});

  大部分情况下你不需要控制这么多细节,要简化上面的代码,我们首先需要依赖基本选项的默认值。如果使用默认值的话,上面的代码可以简化成:

 var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
var directiveDefinitionObject = {
compile: function compile(tElement, tAttrs) {
return function postLink(scope, iElement, iAttrs) { ... }
}
};
return directiveDefinitionObject;
});

  由于大部分的指令只关心实例,并不需要将模板进行变形,所以我们还可以简化成:

 var myModule = angular.module(...);
myModule.directive('directiveName', function factory(injectables) {
return function postLink(scope, iElement, iAttrs) { ... }
});

  上面代码中的factory函数,我们叫工厂函数,它是用来创建指令的。它只会被调用一次:就是当编译器第一次匹配到相应指令的时候,你可以在其中进行任何初始化的工作。调用它时使用的是  $injector.invoke , 所以它遵循所有注入器的规则。

  指令对象的属性有一下:

  • 名称name - 当前作用域的名称
  • 优先级priority - 当一个DOM上有多个指令时,就会需要指定指令执行的顺序。 这个优先级就是用来在执行指令的compile函数前,先排序的。高优先级的先执行。
  • terminal - 该参数用来定义是否停止当前元素上比本指令优先级低的指令,如果值为true,就是正常情况,按照优先级高低的顺序来执行,如果设置为false,就不会执行当前元素上比本指令优先级低的指令。
  • 作用域scope- 如果被定义成:
    • true - 那么就会为当前指令创建一个新的作用域。如果有多个在同一个DOM上的指令要求创建新作用域,那么只有一个新的会被创建。 这一创建新作用域的规则不适用于模板的根节点,因为模板的根节点总是会得到一个新的作用域。

    • {},对象哈希 - 那么一个新的“孤立的”作用域就会被创建。这个“孤立的”作用域区别于一般作用域的地方在于,它不会以原型继承的方式直接继承自父作用域。这对于创建可重用的组件是非常有用的,因为可重用的组件一般不应该读或写父作用域的数据。 这个“孤立的”作用域使用一个对象哈希来表示,这个哈希定义了一系列本地作用域属性,这些属性的值可以有以下几种方式。
      • @ 或 @attr - 将本地作用域成员和DOM属性绑定。使用@实现单向绑定。
      • = 或 =expression - 在本地作用域属性和父作用域属性间建立一个双向的绑定。使用=实现双向绑定。
      • & 或 &attr - 调用父scope里的方法。
  • controller - 这个是指令内部的controller,跟angular中的controller不一样。它的作用是暴露此指令的一些方法给其他指令使用。这个控制器函数是在预编译阶段被执行的,并且它是共享的,这就使得指令间可以互相交流来扩大自己的能力。

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

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

    • E - 元素名称:  <my-directive></my-directive>
    • A - 属性:   <div my-directive="exp"> </div>
    • C - 类名:  <div class="my-directive: exp;"></div>
    • M - 注释:   <!-- directive: my-directive exp -->
  • 模板template - 将当前的元素替换掉。 这个替换过程会自动将元素的属性和css类名添加到新元素上。

  • 模板地址templateUrl - 和template属性一样,只不过这里指示的是一个模板的URL。因为模板加载是异步的,所有编译和链接都会等到加载完成后再执行。

  • 替换replace - 如果被设置成true,那么页面上指令内部里面的内容会被模板替换。比如:<hello><div>这是指令内部的内容</div></hello>,hello指令内部的div内容将会被模板替换掉。

  • transclude -  如果不想让指令内部的内容被模板替换,可以设置这个值为true。一般情况下需要和ngTransclude指令一起使用。 比如:template:"<div>hello every <div ng-transclude></div></div>",这时,指令内部的内容会嵌入到ng-transclude这个div中。也就是变成了<div>hello every <div>这是指令内部的内容</div></div>

  • 编译compile - function compile(tElement, tAttrs, transclude) { ... }

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

    • tElement - template element - 指令所在的元素。对这个元素及其子元素进行变形之类的操作是安全的。

    • tAttrs - template attributes - 这个元素上所有指令声明的属性,这些属性都是在编译函数里共享的。

    • transclude - 一个嵌入的链接函数  function(scope, cloneLinkingFn) 。

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

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

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

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

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

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

参考文档:http://www.tuicool.com/articles/fqiI73M

AngularJS指令的详解的更多相关文章

  1. AngularJS模块的详解

    AngularJS模块的详解 在讲angularjs的模块之前,我们先介绍一下angular的一些知识点: AngularJS是纯客户端技术,完全用Javascript编写的.它使用的是网页开发的常规 ...

  2. ng-repeat指令使用详解

    ng-repeat指令使用详解 link: function(scope,element,attr) scope.$index: if(scope.$last == true){} attr['mng ...

  3. SSI指令使用详解(转)

    什么是 SHTML使用SSI(Server Side Include)的html文件扩展名,SSI(Server Side Include),通常称为“服务器端嵌入”或者叫“服务器端包含”,是一种类似 ...

  4. Java中String的intern方法,javap&amp&semi;cfr&period;jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置

    一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...

  5. IA-32指令解析详解

    IA-32指令解析详解 0x00 前言 这段时间忙于考试,信息论和最优化,还有算法分析,有点让人头大.期间花了几天看SEH机制,能明白个大概,但是对于VC++对于SHE的包装似乎还是不是很明白,发现逆 ...

  6. AngularJS的this详解

    [this详解]                   1.谁最终调用函数,this指向谁.             ① this指向的,永远只可能是对象!!!!!!             ② thi ...

  7. vue自定义指令VNode详解&lpar;转&rpar;

    1.自定义指令钩子函数 Vue.directive('my-directive', {bind: function () {// 做绑定的准备工作// 比如添加事件监听器,或是其他只需要执行一次的复杂 ...

  8. AngularJS开发指南4:指令的详解

    指令是我们用来扩展浏览器能力的技术之一.在DOM编译期间,和HTML元素关联着的指令会被检测到,并且被执行.这使得指令可以为DOM指定行为,或者改变它. AngularJS有一套完整的.可扩展的.用来 ...

  9. AngularJS常用指令用法详解

    ng-class 1>ng-init   ng-bind 11111 2>ng-class 111 3>ng-repeat 3.1-数据绑定     ng-repeat可以绑定数组和 ...

随机推荐

  1. Web安全相关(二):跨站请求伪造(CSRF&sol;XSRF)

    简介 CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对 ...

  2. 查看外网出口IP &amp&semi;&amp&semi; Traceroute

    一.CentOS 查看外网出口IP 1---------------- # curl ifconfig.me 2----------------# curl icanhazip.com 二.Trace ...

  3. shell test 數值 字符串 文件比較

    數值比較 描述 n1 –eq n2 等於 n1 –gt  n2 大於 n1 –ge n2 大於等於 n1 –lt  n2 小於 n1 –le n2 小於等於 n1 –ne n2 不等於   字符串比較 ...

  4. 多媒体音频(audio)

    随着计算机技术的发展,特别是海量存储设备和大容量内存在PC机上的实现,对音频媒体进行数字化处理便成为可能.数字化处理的核心是对音频信息的采样,通过对采集到的样本进行加工,达成各种效果,这是音频媒体数字 ...

  5. 数据挖掘系列(5)使用mahout做海量数据关联规则挖掘

    上一篇介绍了用开源数据挖掘软件weka做关联规则挖掘,weka方便实用,但不能处理大数据集,因为内存放不下,给它再多的时间也是无用,因此需要进行分布式计算,mahout是一个基于hadoop的分布式数 ...

  6. Servlet的一些细节问题

    Servlet的细节问题 1.一个已经注册的Servlet可以被多次映射即: <servlet> <!-- servlet的注册名 --> <servlet-name&g ...

  7. Solr4&period;7从文件创建索引

    索引数据源并不会一定来自于数据库.XML.JSON.CSV这类结构化数据,很多时候也来自于PDF.word.html.word.MP3等这类非结构化数据,从这类非结构化数据创建索引,solr也给我们提 ...

  8. 【原创】shadowebdict开发日记:基于linux的简明英汉字典(二)

    全系列目录: [原创]shadowebdict开发日记:基于linux的简明英汉字典(一) [原创]shadowebdict开发日记:基于linux的简明英汉字典(二) [原创]shadowebdic ...

  9. Super Jumping&excl; Jumping&excl; Jumping&excl;杭电1087

    Description Problem Description Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumpi ...

  10. python的white循环

    # _*_coding:utf-8 _*_import datetimename = 'gyf'passd = 123count =0now = datetime.datetime.now()whil ...