上一篇简单介绍了自定义一个指令的几个简单参数,restrict、template、templateUrl、replace、transclude,这几个理解起来相对容易很多,因为它们只涉及到了表现,而没有涉及行为。这一篇将继续学习ng自定义指令的几个重量级参数,了解了它们之后我们的custom directive将不光能“看”,还要能“动”。开始~

理解compile和link

  不知大家有没有这样的感觉,自己定义指令的时候跟写jQuery插件有几分相似之处,都是先预先定义好页面结构及监听函数,然后在某个元素上调用一下,该元素便拥有了特殊的功能。区别在于,jQuery的侧重点是DOM操作,而ng的指令中除了可以进行DOM操作外,更注重的是数据和模板的绑定。jQuery插件在调用的时候才开始初始化,而ng指令在页面加载进来的时候就被编译服务($compile)初始化好了。

  在指令定义对象中,有compile和link两个参数,它们是做什么的呢?从字面意义上看,编译、链接,貌似太抽象了点。其实可大有内涵,为了在自定义指令的时候能正确使用它们,现在有必要了解一下ng是如何编译指令的。上一篇我有列了一下指令的执行流程,但仅仅列1234有点太对不起观众了,故在此详细分析一下。此知识点相当重要。

指令的解析流程详解

  我们知道ng框架会在页面载入完毕的时候,根据ng-app划定的作用域来调用$compile服务进行编译,这个$compile就像一个大总管一样,清点作用域内的DOM元素,看看哪些元素上使用了指令(如<div ng-modle=”m”></div>),或者哪些元素本身就是个指令(如<mydierc></mydirec>),或者使用了插值指令( {{}}也是一种指令,叫interpolation directive),$compile大总管会把清点好的财产做一个清单,然后根据这些指令的优先级(priority)排列一下,真是个细心的大总管哈~大总管还会根据指令中的配置参数(template,place,transclude等)转换DOM,让指令“初具人形”。

  然后就开始按顺序执行各指令的compile函数,注意此处的compile可不是大总管$compile,人家带着$是土豪,此处执行的compile函数是我们指令中配置的,compile函数中可以访问到DOM节点并进行操作,其主要职责就是进行DOM转换,每个compile函数执行完后都会返回一个link函数,这些link函数会被大总管汇合一下组合成一个合体后的link函数,为了好理解,我们可以把它想象成葫芦小金刚,就像是进行了这样的处理

//合体后的link函数
function AB(){
A(); //子link函数
B(); //子link函数
}

  接下来进入link阶段,合体后的link函数被执行。所谓的链接,就是把view和scope链接起来。链接成啥样呢?就是我们熟悉的数据绑定,通过在DOM上注册监听器来动态修改scope中的数据,或者是使用$watchs监听 scope中的变量来修改DOM,从而建立双向绑定。由此也可以断定,葫芦小金刚可以访问到scope和DOM节点。

  不要忘了我们在定义指令中还配置着一个link参数呢,这么多link千万别搞混了。那这个link函数是干嘛的呢,我们不是有葫芦小金刚了嘛?那我告诉你,其实它是一个小三。此话怎讲?compile函数执行后返回link函数,但若没有配置compile函数呢?葫芦小金刚自然就不存在了。正房不在了,当然就轮到小三出马了,大总管$compile就把这里的link函数拿来执行。这就意味着,配置的link函数也可以访问到scope以及DOM节点。值得注意的是,compile函数通常是不会被配置的,因为我们定义一个指令的时候,大部分情况不会通过编程的方式进行DOM操作,而更多的是进行监听器的注册、数据的绑定。所以,小三名正言顺的被大总管宠爱~

  听完了大总管、葫芦小金刚和小三的故事,你是不是对指令的解析过程比较清晰了呢?不过细细推敲,你可能还是会觉得情节生硬,有些细节似乎还是没有透彻的明白,所以还需要再理解下面的知识点:

compile和link的区别

  其实在我看完官方文档后就一直有疑问,为什么监听器、数据绑定不能放在compile函数中,而偏偏要放在link函数中?为什么有了compile还需要link?就跟你质疑我编的故事一样,为什么最后小三被宠爱了?所以我们有必要探究一下,compile和link之间到底有什么区别。好,正房与小三的PK现在开始。

首先是性能。举个例子:

<ul>
<li ng-repeat="a in array">
<input ng-modle=”a.m” />
</li>
</ul>

我们的观察目标是ng-repeat指令。假设一个前提是不存在link。大总管$compile在编译这段代码时,会查找到ng-repeat,然后执行它的compile函数,compile函数根据array的长度复制出n个<li>标签。而复制出的<li>节点中还有<input>节点并且使用了ng-modle指令,所以compile还要扫描它并匹配指令,然后绑定监听器。每次循环都做如此多的工作。而更加糟糕的一点是,我们会在程序中向array中添加元素,此时页面上会实时更新DOM,每次有新元素进来,compile函数都把上面的步骤再走一遍,岂不是要累死了,这样性能必然不行。

现在扔掉那个假设,在编译的时候compile就只管生成DOM的事,碰到需要绑定监听器的地方先存着,有几个存几个,最后把它们汇总成一个link函数,然后一并执行。这样就轻松多了,compile只需要执行一次,性能自然提升。

另外一个区别是能力。尽管compile和link所做的事情差不多,但它们的能力范围还是不一样的。比如正房能管你的存款,小三就不能。小三能给你初恋的感觉,正房却不能。

我们需要看一下compile函数和link函数的定义:

function compile(tElement, tAttrs, transclude) { ... }

function link(scope, iElement, iAttrs, controller) { ... }   

这些参数都是通过依赖注入而得到的,可以按需声明使用。从名字也容易看出,两个函数各自的职责是什么,compile可以拿到transclude,允许你自己编程管理乾坤大挪移的行为。而link中可以拿到scope和controller,可以与scope进行数据绑定,与其他指令进行通信。两者虽然都可以拿到element,但是还是有区别的,看到各自的前缀了吧?compile拿到的是编译前的,是从template里拿过来的,而link拿到的是编译后的,已经与作用域建立了关联,这也正是link中可以进行数据绑定的原因。

  正房与小三的区别就是性能和能力两个关键字,简记为性能力,我想你永远都不会忘记了吧,真相就是如此的赤裸裸啊~哈哈

  我暂时只能理解到这个程度了。实在不想理解这些知识的话,只要简单记住一个原则就行了:如果指令只进行DOM的修改,不进行数据绑定,那么配置在compile函数中,如果指令要进行数据绑定,那么配置在link函数中。

无奈的结束

  理解指令的处理流程以及compile和link的区别,花费了我大量的时间。资料太少了,官方文档翻来覆去看,最后理解到了这个程度,但总觉得还是差那么一点,没有100%理解到位。今天太困了,就记录到此处吧,以后有了新的理解再做补充。

  其实这篇的标题我想写(下)的,直接把scope、require、controller一并介绍完毕,现在看来是不可能了,因为这几个参数也是需要重点理解的,这样下去篇幅又hold不住了。这里就当是预报好了。。。囧。。。以前觉得没有附图和代码示例的博客不是好博客,现在反倒觉得要码出这么多字来,也是需要下功夫的。

走进AngularJs(四)自定义指令----(中)的更多相关文章

  1. 走进AngularJs(三)自定义指令-----(上)

    一.有感而发的一些话 在学习ng之前有听前辈说过,angular上手比较难,初学者可能不太适应其语法以及思想.随着对ng探索的一步步深入,也确实感觉到了这一点,尤其是框架内部的某些执行机制,其复杂程度 ...

  2. 走进AngularJs(五)自定义指令----(下)

    自定义指令学习有段时间了,学了些纸上谈兵的东西,还没有真正的写个指令出来呢...所以,随着学习的接近尾声,本篇除了介绍剩余的几个参数外,还将动手结合使用各参数,写个真正能用的指令出来玩玩. 我们在自定 ...

  3. Angularjs进阶笔记(2)-自定义指令中的数据绑定

    有关自定义指令的scope参数,网上很多文章都在讲这3种绑定方式实现的效果是什么,但几乎没有人讲到底怎么使用,本篇希望聊聊到底怎么用这个话题. 一. 自定义指令 自定义指令,是Angularjs用来实 ...

  4. 带你走近AngularJS - 创建自定义指令

    带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自定义指令 ------------- ...

  5. Angular6在自定义指令中使用@HostBingDing() 和@HostListener()

    emmm,,,最近在为项目的第二阶段铺路,偶然看到directive,想想看因为项目已经高度集成了第三方组件,所以对于自定义指令方面的经验自己实在知之甚少,后面经过阅读相关资料,总结一篇关于在自定义指 ...

  6. AngularJS学习笔记(四) 自定义指令

    指令(directive)是啥?简单来说就是实现一定功能的XXX...之前一直用的ng-model,ng-click等等都是指令.当我有一个ng没提供的需求的时候,就可以自定义个指令.指令的好处显而易 ...

  7. AngularJS笔记--自定义指令

    在前端开发中, 我们会遇到很多地方都会用到同一种类型的控件.AngularJS提供了自定义指令功能,我们可以在指令里面定义特定的html模板.提供给前台html调用. 一. 指令的简单定义.  下面定 ...

  8. angularJS 使用自定义指令输出模板

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <script sr ...

  9. 走进AngularJs(二) ng模板中常用指令的使用方式

    通过使用模板,我们可以把model和controller中的数据组装起来呈现给浏览器,还可以通过数据绑定,实时更新视图,让我们的页面变成动态的.ng的模板真是让我爱不释手.学习ng道路还很漫长,从模板 ...

随机推荐

  1. html总集

    3.1清单格式:<ul> <li>...</li></ul><li>的属性:type disc 实心圆(默认) circle 空心圆 squ ...

  2. 【转载】java项目中经常碰到的内存溢出问题: java.lang.OutOfMemoryError: PermGen space, 堆内存和非堆内存,写的很好,理解很方便

    Tomcat Xms Xmx PermSize MaxPermSize 区别 及 java.lang.OutOfMemoryError: PermGen space 解决 解决方案 在 catalin ...

  3. 手机safari图片上传竖变横处理

    在手机safari上传图片时,竖着的照片会变成横着的照片,以下程序片段利用图片exif信息把图片旋转回去,代码抄自php.net官网. http://php.net/manual/zh/functio ...

  4. Python赋值语句与深拷贝、浅拷贝的区别

    参考:http://stackoverflow.com/questions/17246693/what-exactly-is-the-difference-between-shallow-copy-d ...

  5. 从多列的DataTable里取需要的几列(转)

    方法一: 也是广为人知的一种: YourDataTable.Columns.Remove("列名"); 但是这种情况只适合于去掉很少列的情况. 如果有很多列我却只要一两列呢,那就得 ...

  6. python __call__内置函数

    __call__实现可以直接调用对象的作用

  7. C语言的选择和循环上机题目(部分)

    /*(1)某市不同车牌的出租车3公里的起步价和计费分别为:夏利7元/公里,3公里以外2.1元/公里:富康8元/公里,3公里以外2.4元/公里:桑塔纳9元,3公里以外2.7元/公里.编程:从键盘输入乘车 ...

  8. 一些比较常用的Linux命令

    我有一些是我是参考别人的,忘记是谁了,在这里要感谢一下ta. #命令格式就是就是由命令+空格+一些命令用法的选项(可以选择多个用法)+空格+/+目录名或者文件名,有些是直接打命令就可以了,比如ls - ...

  9. 【转载】【树形DP】【数学期望】Codeforces Round #362 (Div. 2) D.Puzzles

    期望计算的套路: 1.定义:算出所有测试值的和,除以测试次数. 2.定义:算出所有值出现的概率与其乘积之和. 3.用前一步的期望,加上两者的期望距离,递推出来. 题意: 一个树,dfs遍历子树的顺序是 ...

  10. JavaScript标准库之 - Math

    属性 Math.E 欧拉常数,也是自然对数的底数, 约等于 2.718. Math.LN2 2的自然对数, 约等于0.693. Math.LN10 10的自然对数, 约等于 2.303. Math.L ...