此处将为大家介绍关于Angular.js中的compilepre-linkpost-link选项的个人理解的详细内容,并且为您解答有关angularjs$scope的相关问题,此外,我们还将为您介绍关
此处将为大家介绍关于Angular.js中的compile pre-link post-link选项的个人理解的详细内容,并且为您解答有关angularjs $scope的相关问题,此外,我们还将为您介绍关于anagularJs指令的controller,link,compile有什么不同、Angular Compiler选项、Angular Directive: link vs compile vs controller、angular 指令详解(一)compile与link的有用信息。
本文目录一览:- Angular.js中的compile pre-link post-link选项的个人理解(angularjs $scope)
- anagularJs指令的controller,link,compile有什么不同
- Angular Compiler选项
- Angular Directive: link vs compile vs controller
- angular 指令详解(一)compile与link
Angular.js中的compile pre-link post-link选项的个人理解(angularjs $scope)
AngularJS的生命周期
在AngularJS的生命周期中,分为编译和链接两个阶段。
在编译阶段中,每一个指令可能有会有另外一个指令,AngularJS遍历他们形成了模板树,之后会返回一个模板函数,而在模板函数返回之前DOM都是没有形成的,所以此时ng-repeat指令就会生效。
而在编译完成之后,会返回一个编译函数,这个编译函数会返回一个总的将所有子指令模板合并在一起的模板函数,并且交给链接阶段。在链接阶段中,我们可以将作用域scope和DOM进行链接,并且对每一个函数的模板的实例进行链接或者监听器的注册。
这个阶段中的三个选项 compile pre-link post-link
这个三个指令并不是完全能用得到,特别是compile,这个指令在实践中,并不会频繁的使用。但是理解这个三个指令的工作机制对于我们理解AngluarJS的生命周期和运作过程有非常重要的作用。
首先看看compile
compile意思是我们希望指令和数据在放入DOM前进行对DOM的操作,因为我们从上一节生命周期中知道,在没有链接之前,我们的DOM虽然生成了,但是我们可以修改DOM,例如添加或者删除节点。但是我们并不推荐这样做。
compile指令可以返回一个对象或者函数,这里我们可以利用Angular的DOM操作element来实现
angular.module('myApp',[]) .directive('myDirective',function(){ return{ compile:function(tEle,tAttrs,transcludeFn){ //这里进行DOM的操作 return function(scope,ele,attrs){ //在这里进行链接函数的链接 } } } });
注意我们只要使用了compile选项就会默认互斥link选项 这样link选项的所有都会被重写。
而且我在compile选项中的函数用了tEle 和tAtts 这是因为这里操作的还没有实例化的template,这里还没有进行链接,所以没有scope和实例。
再来看看Link
link指的是我们在compile执行完之后将作用域和DOM进行链接,一般我们指的link都是Postlink,因为如果你直接写Link指令就是默认变成postlink。
postlink的用法
postlink是我们最经常用的一个选项,当然我们默认只会写上link,就是指postlink,他可以为我们链接作用域和编写业务和逻辑代码。
prelink的用法
prelink应该是我们理解Angular中最难的一个选项,prelink会在Postlink之前执行,他在compile之后执行。在prelink中写的是我们在compile DOM操作之后但是又是在postlink执行的业务代码。
实例代码:
angular.module('myApp',transcludeFn){ //这里进行DOM的操作 return { pre: function(scope,iElem,iAttrs){ console.log(name + ': pre link => ' + iElem.html()); },post: function(scope,iAttrs){ console.log(name + ': post link => ' + iElem.html()); } } } } });
compile pre-link post-link 执行的顺序
首先应该是compile和pre-link是以此的执行的,他们执行完之后post-link才会执行。如果有多个嵌套的指令元素,那么compile 和pre-link会依次执行,而它们执行完后postlink才会执行。
且,pre-link会反向执行,从内到外的执行来保证执行顺序。
这里引用jingxian的文章
传入compile pre-link post-link 的参数解析
当compile 运行的时候,我们的DOM还会修改所以这里的参数都是模板 例如tEle tAttrs 当进入链接时pre-link传入的参数这时是还是tEle tAttrs 因为这里还是链接之前当然pros-link传入的作用域和元素都是实例我们用,iElement iAttrs scope 如果存在require引入新的作用域的话,我们会多一个controller的参数指向引入的控制器。
anagularJs指令的controller,link,compile有什么不同
<div>
/directives.js增加exampleDirective
phonecatDirectives.directive('exampleDirective','E''Hello {{number}}!
'cope,$element){
$scope.number = $scope.number + "22222 "cope,el,attr) {
scope.number = scope.number + "33333 "cope,element,attributes) {
scope.number = scope.number + "44444 "cope,attributes) {
scope.number = scope.number + "55555 "<span>//<span>controller.js添加
dtControllers.controller('directive2',['$scope'<span>,<span>function<span>($scope) {
$scope.number = '1111 '<span>;
}
]);
<span>//<span>html
<body ng-app="phonecatApp">
<div ng-controller="directive2">
Angular Compiler选项
> useDebug – 打开调试
> useJit – 不清楚(仅在one place使用)
> defaultEncapsulation – 设置默认样式封装
>提供者 – 不是很清楚(与ngModule装饰器是否相同?)
> missingTranslation – 策略如果缺少翻译密钥该怎么办
> enableLegacyTemplate – 支持模板标记(已弃用)
解决方法
是使用codegen还是解释模式.
Codegen是默认模式,因此我们可以在浏览器开发工具中看到输出.在此模式下,angular将在编译期间收集的所有语句转换为具有浏览器内存中可执行代码的文件.
我知道使用此选项的三个地方
>模块工厂生成https://github.com/angular/angular/blob/4.3.x/packages/compiler/src/jit/compiler.ts#L146
NG:///AppModule/module.ngfactory.js
>组件工厂生成https://github.com/angular/angular/blob/4.3.x/packages/compiler/src/jit/compiler.ts#L282
NG:///AppModule/Component_Host.ngfactory.js
NG:///AppModule/Component.ngfactory.js.
> styleUrls代码生成https://github.com/angular/angular/blob/4.3.x/packages/compiler/src/jit/compiler.ts#L307
NG:///css/0app/app.css.ngstyle.js
解释模式意味着角度将像解释器一样工作.将直接执行先前步骤(词法分析,解析,语义分析,优化)中生成的语句. Angular不会像在codegen模式中那样将代码转换为组件和模块ngfactories.相反,角度使用工厂的特殊包装,即
function _declareFn( varNames: string[],statements: o.Statement[],ctx: _ExecutionContext,visitor: StatementInterpreter): Function { return (...args: any[]) => _executeFunctionStatements(varNames,args,statements,ctx,visitor); }
然后它会在每次必要时执行这些包装器.(例如,当你处理事件时,当angular运行updateDirectives,updateRenderer等时)每次使用StatementVisitor来遍历所有语句.
最初解释模式也用于DART https://github.com/angular/angular/commit/2b34c88b69af8b0031fdb7006327bb8260e23dda#diff-ba3d6dc88c6e1cef871391a7843a614eR167但现在这种模式几乎不使用AFAIK.
供应商
如果我们有两个具有相同令牌的提供者,则第二个提供者“获胜”.
因此,提供商选项是覆盖默认COMPILER_PROVIDERS的一项很棒的功能
比如我们可以
1)自定义DomElementSchema
> Add custom elements and attributes to compiler schema
2)使用特定的DirectiveResolver覆盖模板
> Using DirectiveResolver to alter @Component metadata
3)覆盖ResourceLoader
> https://github.com/angular/angular/issues/13286
4)覆盖Parser,TemplateParser以可视化编译器的工作
> https://alexzuza.github.io/enjoy-ng-parser/
等等…
我们不能对NgModule提供程序做同样的事情,因为编译器使用专用注入器(下图中的JitCompiler注入器)https://github.com/angular/angular/blob/4.3.x/packages/compiler/src/jit/compiler_factory.ts#L115,编译发生在https://github.com/angular/angular/blob/4.3.x/packages/core/src/application_ref.ts#L326-L329 @NgModule提供程序解析之前https://github.com/angular/angular/blob/4.3.x/packages/core/src/application_ref.ts#L297
假设我们有app:
my-app level1 level2 level3
然后依赖解析算法将如下所示:
如果我们对所有级别https://plnkr.co/edit/AYExeiYRSQ4H8LiQEgKo?p=preview使用延迟加载
my-app router-outlet level1 router-outlet level2 router-outlet level3
它将转变为
为了简化,我在图中省略了路由器出口喷油器.
有关更多详细信息,请参阅设计文档:
> https://docs.google.com/document/d/1OEUIwc-s69l1o97K0wBd_-Lth5BBxir1KuCRWklTlI4
Angular Directive: link vs compile vs controller
Compile :
This is the phase where Angular actually compiles your directive. This compile function is called just once for each references to the given directive. For example, say you are using the ng-repeat directive. ng-repeat will have to look up the element it is attached to, extract the html fragment that it is attached to and create a template function.
If you have used HandleBars, underscore templates or equivalent, its like compiling their templates to extract out a template function. To this template function you pass data and the return value of that function is the html with the data in the right places.
The compilation phase is that step in Angular which returns the template function. This template function in angular is called the linking function.
Linking phase :
The linking phase is where you attach the data ( $scope ) to the linking function and it should return you the linked html. Since the directive also specifies where this html goes or what it changes, it is already good to go. This is the function where you want to make changes to the linked html, i.e the html that already has the data attached to it. In angular if you write code in the linking function its generally the post-link function (by default). It is kind of a callback that gets called after the linking function has linked the data with the template.
Controller :
The controller is a place where you put in some directive specific logic. This logic can go into the linking function as well, but then you would have to put that logic on the scope to make it "shareable". The problem with that is that you would then be corrupting the scope with your directives stuff which is not really something that is expected. So what is the alternative if two Directives want to talk to each other / co-operate with each other? Ofcourse you could put all that logic into a service and then make both these directives depend on that service but that just brings in one more dependency. The alternative is to provide a Controller for this scope ( usually isolate scope ? ) and then this controller is injected into another directive when that directive "requires" the other one. See tabs and panes on the first page of angularjs.org for an example.
angular 指令详解(一)compile与link
原文地址:https://987.tw/2014/09/03/ang...
AngularJS directives是令人惊艳的。它允许你创造高度语意且可重复利用的元件。在某种意义上你可以认为它是极致的web components先驱者。
有许多很棒的文章,甚至是书籍,在教导你如何撰写自己的directives。相较之下,只有少许的资讯谈到有关compile及link函式的差异,更不用说有关pre-link及post-link函式差别。
大多数的导引只有简单地提到compile函式主要由AngularJS在内部使用,并且建议你只要用link函式,应该能够涵盖大多数的使用案例。
这是十分不幸的,因为了解这些函式其中的差异能够提升你的能力,更加的了解AngularJS内部运作,并且订制出更好的directives。
所以跟着我,文章最后你将会正确地了解这些函式是什么以及什么时候该使用它们。
本文假设你已经了解什么是AngularJS directive。如果不了解,我强烈建议你先阅读AngularJS开发者指南的directive章节。
AngularJS如何处理directives?
在我们开始之前,让我打断一下,先了解AngularJS是如何处理directives。
(1)当浏览器渲染(render)页面时,基本地读取HTML标签,建立一个DOM,当DOM准备好时,广播(broadcast)出一个事件(event)。
(2)当你使用<script></script>标签引入你的AngularJS程式码到页面时,AngularJS会监听(listen)该事件,一旦该事件发出,AngularJS便会开始走遍(traversing)DOM,寻找所有元素(element)中的属性(attribute )是否具有ng-app。
(3)一旦找到具有该属性的元素,AngularJS便以该元素作为起始点,进行DOM 处理。如果在html元素的属性内设定ng-app,那么AngularJS将会从html元素开始处理 DOM。
(4)从起始点开始,AngularJS递回地调查所有子元素,从你的AngularJS应用程式中所定义的directives中去找寻相对应的样式。
AngularJS如何处理元素,取决于实际定义directive的物件(译注:directive deFinition object)。你可以预先定义compile函式或link函式,两者可同时存在。或者选择性的定义pre-link及post-link这两个函式来取代link函式,
所以,这些函式有什么差异?为什么及何时该使用这些函式?
坚持下去...
程式码
为了解释这些差异,我会用程式码来做示范,希望能够更容易的理解。
考虑下列HTML标签:
<level-one> <level-two> <level-three> Hello {{name}} </level-three> </level-two> </level-one>
以及下列JavaScript:
var app = angular.module('plunker',[]); function createDirective(name){ return function(){ return { restrict: 'E',compile: function(tElem,tAttrs){ console.log(name + ': compile'); return { pre: function(scope,iElem,iAttrs){ console.log(name + ': pre link'); },post: function(scope,iAttrs){ console.log(name + ': post link'); } } } } } } app.directive('levelOne',createDirective('levelOne')); app.directive('levelTwo',createDirective('levelTwo')); app.directive('levelThree',createDirective('levelThree'));
目标很简单:让AngularJS处理巢状的三个directives,而每个directive都有自己的compile、pre-link及post-link函式,各函式输出讯息至console,我们可以借此作为识别。
这让我们可以一睹AngularJS是如何在背后处理这些directives。
输出结果:
这是console输出结果的截图:
如果你要自己试试看,开启这个plnkr链接,并在打开浏览器的Console。
开始分析
第一件要注意的是,函式呼叫的顺序:
// COMPILE階段 // levelOne: compile函式已呼叫 // levelTwo: compile函式已呼叫 // levelThree: compile函式已呼叫 // PRE-LINK階段 // levelOne: pre link函式已呼叫 // levelTwo: pre link函式已呼叫 // levelThree: pre link函式已呼叫 // POST-LINK階段 (注意到反向順序) // levelThree: post link函式已呼叫 // levelTwo: post link函式已呼叫 // levelOne: post link函式已呼叫
这个清除地展示AngularJS一开始compile所有directives,compile阶段尚未连结scope,link阶段也分成pre-link及post-link阶段。
注意到呼叫compile及pre-link的顺序是一致的,但是呼叫post-link的顺序则是相反的。
所以在这里我们可以已经清处的辨别这几个不同的阶段,但是compile与pre-link又有什么不同呢?它们也有同样的顺序,为什么要将它们分开?
文件物件模型(DOM)
稍微深入一些,进一步修改JavaScript,呼叫时一并输出元素的DOM:
var app = angular.module('plunker',tAttrs){ console.log(name + ': compile => ' + tElem.html()); return { pre: function(scope,iAttrs){ console.log(name + ': pre link => ' + iElem.html()); },iAttrs){ console.log(name + ': post link => ' + iElem.html()); } } } } } } app.directive('levelOne',createDirective('levelThree'));
注意到console.log额外的输出讯息。没有任何更动,仍然是最原始的标签。
这应该能让我们更详细的了解函式的来龙去脉。
让我们再次执行程式码。
输出结果:
观察
输出DOM结果透漏某些有趣的东西:compile与pre-link阶段的DOM不一样。
所以,发生什么事?
Compile
我们已经学习到当AngularJS侦测DOM准备好时,会进行DOM处理。
所以,当AngularJS开始走遍DOM,它遇见<level-one>元素,并从它的directive定义(directive deFinition)中得知需要执行某些行为。
因为在levelOne的directive定义中,定义了compile函式,所以会呼叫此函式并带入元素DOM作为函式的参数。
如果你靠近一点你会看到,在这个时机点,元素的DOM仍然是最初刚开始的DOM,系由浏览器根据原始HTML标签所创造出来的DOM。
在AngularJS里,经常用样板元素(template element)来提到原始的DOM,因此基于这个原因我个人用tElem来作为compile函式内的参数名称,用来表示样板元素。
当levelOne的compile执行之后,AngularJS更深入且递回地走入DOM,对<level-two>及<level-three>重复相同的编译步骤。
Post-link
在我们深入pre-link函式前,让我们先看一下post-link函式。
如果你产生的directive只有link函式,AngularJS会将它当作是post-link函式。因为这个原因我们要在先讨论它。
一旦AngularJS走到DOM的最后(底)并执行完所有compile函式,它会往回(上)走并且执行所有关联的post-link函式。
现在DOM是用反方向在走遍,因此呼叫post-link函式是相反的顺序。所以前几分钟看到相反顺序觉得很奇怪,现在开始觉得合理了。
这相反顺序保证所有的子元素post-link会先被执行,接着才是父元素的post-link。
所以,当<level-one>的post-link函式被呼叫,我们可以保证<level-two>及<level-three>的post-link已经被呼叫过。
这就是为什么它被认为是用来加入你的directive逻辑最安全以及预设的地方。
那元素的DOM呢?为什么在这里它们是不同的?
当AngularJS呼叫了directive的compile函式之后,它会产生一个样板元素(template element)的实例元素(instance element)(通常称之为消灭实体),并且提供一个scope给这个实体。这个scope可以是全新的scope、继承的子scope或孤立的scope,取决于相对应directive定义物件内scope属性设定。
所以,到连结阶段的时候,实例元素及scope已经可以开始使用,并且AngularJS会将它作为函式参数传递到post-link函式。
Pre-link
当撰写post-link函式时,你可以保证所有子元素的post-link函式已经执行过。
在大多数的案例中,这个非常合理,因此它也是最常用来撰写directive程式码的地方。
然而,AngularJS提供了一个附加的钩子,称之为pre-link函式,程式码会先被执行,抢先在所有子元素的post-link被执行之前。
再次强调:
pre-link函式保证所有子元素的post-link被执行前,先执行pre-link函式,并且是在实体元素中执行。
所以当相反顺序的呼叫post-link十分合理,那原始顺序的呼叫pre-link也是十分合理。
回顾
如果我们回顾之前原始输出,我们可以清晰的辨认出发生什么事:
// 这里的元素仍然是最原始的样板标签 // COMPILE 阶段 // levelOne: 原始DOM中呼叫compile函式 // levelTwo: 原始DOM中呼叫compile函式 // levelThree: 原始DOM中呼叫compile函式 // 从这里开始,元素已经实例化且綁定了ScopE // (例:NG-REPEAT 已有多重实例) // PRE-LINK 階段 // levelOne: 元素实例中呼叫pre link函式 // levelTwo: 元素实例中呼叫pre link函式 // levelThree: 元素实例中呼叫pre link函式 // POST-LINK 阶段 (注意到順序相反) // levelThree: 元素实例中呼叫post link函式 // levelTwo: 元素实例中呼叫post link函式 // levelOne: 元素实例中呼叫post link函式
摘要
回顾中我们可以描述不同的函式及使用案例如下:
Compile函式
在AngularJS产生实例及scope之前,使用compile函式来更动原始DOM(样板元素)。
它可以有多个元素实例,但只会有一个样板元素。ng-repeat就是这个案例的一个完美范例。它让compile成为最佳的地方来进行更动DOM,之后才会套用所有实例,因为只会执行一次,所以当你要消灭很多实例时,可以获得很多效率上的提升。
样板的元素及属性都会作为参数传递到compile函式,但不会有scope传入,因为还没准备好:
/** * Compile函式 * * @param tElem - 样板元素 * @param tAttrs - 样板元素的属性 */ function(tElem,tAttrs){ // ... };
Pre-link函式
当AngularJS已经compile子元素,在任何子元素的post-link执行之前,使用pre-link函式来实作逻辑。
Scope、实例元素及实例属性都会作为参数传递到pre-link函式:
/** * Pre-link函式 * * @param scope - 關連於此實例的scope * @param iElem - 實例元素 * @param iAttrs - 實例元素的屬性 */ function(scope,iAttrs){ // ... };
Post-link函式
使用post-link来执行逻辑,该逻辑知道所有子元素已经编译,并且所有子元素的pre-link及post-link都已经被执行。
基于这个理由,post-link认为是最安全及预设的地方来撰写你的程式码。
Scope、实例元素及实例属性都会作为参数传递到post-link函式:
/** * Post-link函式 *
@param scope - 關連於此實例的scope
@param iElem - 實例元素
@param iAttrs - 實例元素的屬性
*/
function(scope,iAttrs){
// ...
};
结论
到目前为止,但愿你有清楚的理解关于compile、pre-link及post-link之间的差异。
如果没有且你很认真的在做AngularJS开发,我强烈建议你再读一次文章,直到你有稳固的抓住其运作原理。
了解这个重要的概念将会让你更容易理解原生的AngularJS directive是如何运作,并且如何最佳化你订制的directives。
今天关于Angular.js中的compile pre-link post-link选项的个人理解和angularjs $scope的讲解已经结束,谢谢您的阅读,如果想了解更多关于anagularJs指令的controller,link,compile有什么不同、Angular Compiler选项、Angular Directive: link vs compile vs controller、angular 指令详解(一)compile与link的相关知识,请在本站搜索。
本文标签: