上一篇简单介绍了自定义一个指令的几个简单参数,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框架中创建自定义指令来封装ECharts 2的雷达图。ECharts是一款由百度开发的开源JavaScript图表库,它提供了丰富的可视化图表类型,包括雷达图。AngularJS是一个强大的前端...
在这个场景中,我们关注的是如何利用AngularJS的自定义指令来封装ECharts 2的折线图功能。ECharts是一个基于JavaScript的开源可视化库,它提供了丰富的图表类型,包括折线图、柱状图、饼图等,适用于各种数据展示...
在本文中,我们将深入探讨如何在 AngularJS 中创建自定义指令来封装 ECharts 2 的柱状图。ECharts 是一个基于 JavaScript 的数据可视化库,它提供了丰富的图表类型,包括柱状图、折线图、饼图等。AngularJS 是一个...
自定义指令是AngularJS中非常强大和灵活的一个特性,它允许开发者封装和复用界面行为。接下来,我们将详细解释自定义指令的原理、实现步骤、实现方法以及相关的注意事项。 ### 指令的原理 在AngularJS中,指令本质...
"angularjs-dropdown-multiselect"是一个专门用于创建下拉多选框的AngularJS指令,它使得在Web应用中实现多选下拉菜单变得极其简单。该指令集成了基本的多选、搜索过滤、分组等功能,极大地提高了用户体验。其主要...
AngularJs-UI, AngularJs Pagination Angularjs分页 -- Want to be the best pagination.
在本文中,我们将深入探讨如何在古老的Internet Explorer 8(IE8)中使用AngularJS 1.3构建前端项目。由于AngularJS 1.3原生不再支持IE8,因此需要一些额外的工作来确保兼容性。`angular.js-ie8-builds-master`这个...
"AngularJS--angular-phonecat"是一个经典的入门教程,旨在帮助初学者理解AngularJS的核心概念和工作原理。尽管描述中提到这个项目可能与网上的教程存在一些小差异且没有包含测试部分,但它仍然是学习AngularJS的一...
在本文中,我们将深入探讨基于AngularJS的前端项目——AngularJS-nvd3-directives,以及如何利用这个库来创建交互式的数据可视化应用。NVD3是一个JavaScript库,它基于D3(Data-Driven Documents)库,专为创建可...
4. `directives.js`:可能包含自定义指令,用于扩展AngularJS的功能,例如验证输入或创建复杂的UI组件。 5. `templates` 文件夹:存放各个视图的HTML模板,与ngRoute配置中的路由对应。 6. `styles.css` 或 `...
"前端项目-angularjs-color-picker" 是一个专门为 AngularJS 框架设计的颜色选择器指令,它允许开发者在 AngularJS 应用中集成色彩选择功能,提供用户友好的交互体验。 **AngularJS 简介** AngularJS 是一个由 ...
在"myforce-angularjs-dropdown-multiselect"项目中,"dropdown-multiselect"是一个自定义AngularJS指令。指令是AngularJS中的一个强大工具,允许我们扩展HTML的语义,创建可重用的UI组件。在这个特定的指令中,它...
本教程将通过"angularjs-chapter1-示例.rar"中的实践案例,深入浅出地讲解AngularJS的基本概念和核心特性,帮助初学者快速上手。 1. **AngularJS简介** AngularJS是MVC(Model-View-Controller)架构的实现,它...
在AngularJS中,指令是用于扩展HTML的一种机制,它们让开发者可以定义自定义的DOM行为。"angularjs指令 下拉框"这个主题聚焦于如何利用AngularJS创建一个自定义的下拉框(Dropdown)指令。下拉框在Web开发中非常常见...
angularjs-chapter3-示例.rar
本篇将详细解析"angularjs-chapter4-示例.rar"中所涵盖的第四章核心概念及实战应用。 在AngularJS的第四章中,主要探讨了以下几个关键知识点: 1. **双向数据绑定**:AngularJS的核心特性之一,它实现了视图与模型...
在介绍AngularJS过滤器-filter与ng-repeat的配合使用时,我们首先需要了解这两个指令在AngularJS框架中所扮演的角色。AngularJS是一个开源的前端框架,由Google支持,广泛用于开发动态Web应用程序。它通过引入双向...
在AngularJS中,自定义指令通过`@Directive`装饰器声明,其基本结构包括: ```javascript app.directive('directiveName', function() { return { restrict: 'AECM', // A - attribute, E - element, C - class, ...
在这个过程中,AngularJS会构建内置模块`ng`,并创建相关的指令和提供者。 6. **构建内置模块ng**: - 内置模块`ng`包含了一系列基本的指令和服务,这些组件构成了AngularJS的核心功能。 7. **注册核心提供者**:...
在这个实例中,我们将深入探讨AngularJS的ng-value指令,以及如何在实际应用中使用它。 ng-value指令主要用于绑定输入元素的值,它可以将模型(model)的值直接赋给HTML元素的value属性。这在处理表单数据时特别...