繼續上一篇:angular學習筆記(三十)-指令(7)-compile和link(1)
上一篇講了compile函式的基本概念,接下來詳細講解compile和link的執行順序.
看一段三個指令巢狀的程式碼:
html:
<body> <div ng-controller="compileCtrl"> <level-one> <level-two> <level-three> hello,{{name}} </level-three> </level-two> </level-one> </div> </body>
js:
/*20.8.2 指令-compile和link*/ var appModule = angular.module('dirAppModule',[]);
appModule.controller('compileCtrl',function($scope){
$scope.name="code_bunny"
});
appModule.directive('levelOne',function(){ return { restrict:'E', compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelOne'); return { pre:function(){ console.log('pre→'+'levelOne') }, post:function(){ console.log('post→'+'levelOne') } } } } }); appModule.directive('levelTwo',function(){ return { restrict:'E', compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelTwo'); return { pre:function(){ console.log('pre→'+'levelTwo') }, post:function(){ console.log('post→'+'levelTwo') } } } } }); appModule.directive('levelThree',function(){ return { restrict:'E', compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelThree'); return { pre:function(){ console.log('pre→'+'levelThree') }, post:function(){ console.log('post→'+'levelThree') } } } } });
得到結果:
因此,他們的執行順序如下:
1.從外層到內層執行指令的compile函式
2.compile執行完畢以後,從外層到內層執行指令的pre-link函式
3.pre-link全部執行完以後,從內層到外層執行指令的post-link函式
程式碼測試地址:http://jsfiddle.net/9hoqvtja/1/
然後我們修改一下js程式碼如下:
/*20.8.2 指令-compile和link*/ appModule.directive('levelOne',function(){ return { restrict:'E', scope:true, compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelOne'+tEle.html()); return { pre:function(scope,iEle,iAttrs){ console.log('pre→'+'levelOne'+iEle.html()) }, post:function(scope,iEle,iAttrs){ console.log('post→'+'levelOne'+iEle.html()) } } } } }); appModule.directive('levelTwo',function(){ return { restrict:'E', scope:true, compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelTwo'+tEle.html()); return { pre:function(scope,iEle,iAttrs){ console.log('pre→'+'levelTwo'+iEle.html()) }, post:function(scope,iEle,iAttrs){ console.log('post→'+'levelTwo'+iEle.html()) } } } } }); appModule.directive('levelThree',function(){ return { restrict:'E', scope:true, compile:function(tEle,tAttrs,trans){ console.log('compile→'+'levelThree'+tEle.html()); return { pre:function(scope,iEle,iAttrs){ console.log('pre→'+'levelThree'+iEle.html()) }, post:function(scope,iEle,iAttrs){ console.log('post→'+'levelThree'+iEle.html()) } } } } });
我們給指令新增scope屬性,在列印的過程中加入列印tEle和iEle的內容,結果如下:
可以看到,才compile階段列印出的元素,是沒有class屬性的,但是在pre-link和post-link階段列印出的元素,class屬性為ng-scope ng-binding.
原因是:
compile階段得到的元素是tElement,也就是templateElement,是原始的元素.
link階段(無論是pre-link還是post-link),得到的是元素是iElement,也就是instanceElement,是經過compile編譯後的元素的例項.
那麼原始的元素和元素的例項有什麼區別呢? 我的理解(不一定對)是:tElement就是最原始的元素,也就會說,頁面裡寫的html是啥,它就是啥.而iElement就經過了angular的編譯處理了.他具體處理了一些什麼事情,我現在不知道,但是就這個例子,可以看到,它至少處理了'給元素繫結scope作用域','對元素裡的資料與模型進行雙向繫結',當然他一定還處理了很多其他的事情...這就是為什麼compile是沒有scope引數的,因為它還沒有編譯嘛~
程式碼測試地址:http://jsfiddle.net/0kgn110u/1/
總結一下剛才講的所有知識:
1.compile函式的執行順序是從父元素向子元素執行.當某個指令的compile被執行時,它的父元素的compile都已經被執行了.它的tEle引數和tAttrs引數,指的的原始的元素和原始元素的屬性,原始元素沒有經過angular編譯.
2.pre-link函式的執行順序是從父元素向子元素執行.當某個指令的pre-link被執行時,它的父元素和它自己的compile函式,以及它的父元素的pre-link函式都已經被執行了.它的iEle引數和iAttrs引數,指的是經過ng編譯的元素.
3.post-link函式的執行順序是從子元素向父元素執行.當某個指令的post-link被執行時,它的父元素和它自己的compile函式,以及它的子元素的post-link函式都已經被執行了.它的iEle函式和iAttrs引數,指的是,經過ng編譯的元素.
參考文獻:[譯]ng指令中的compile與link函式解析
但是上面說的這一切,當指令中有template(templateUrl)的時候,它compile和link的執行順序就不是這樣的了.下一篇繼續講解這種情況.