最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

angularjs指令中的compile與link函數(shù)詳解

 更新時(shí)間:2014年12月06日 10:25:14   投稿:junjie  
這篇文章主要介紹了angularjs指令中的compile與link函數(shù)詳解,本文同時(shí)訴大家complie,pre-link,post-link的用法與區(qū)別等內(nèi)容,需要的朋友可以參考下

通常大家在使用ng中的指令的時(shí)候,用的鏈接函數(shù)最多的是link屬性,下面這篇文章將告訴大家complie,pre-link,post-link的用法與區(qū)別.

angularjs里的指令非常神奇,允許你創(chuàng)建非常語(yǔ)義化以及高度重用的組件,可以理解為web components的先驅(qū)者.

網(wǎng)上已經(jīng)有很多介紹怎么使用指令的文章以及相關(guān)書(shū)籍,相互比較的話,很少有介紹compile與link的區(qū)別,更別說(shuō)pre-link與post-link了.

大部分教程只是簡(jiǎn)單的說(shuō)下compile會(huì)在ng內(nèi)部用到,而且建議大家只用link屬性,大部分指令的例子里都是這樣的

這是非常不幸的,因?yàn)檎_的理解這些函數(shù)的區(qū)別會(huì)提高你對(duì)ng內(nèi)部運(yùn)行機(jī)理的理解,有助于你開(kāi)發(fā)更好的自定義指令.

所以跟著我一起來(lái)看下面的內(nèi)容一步步的去了解這些函數(shù)是什么以及它們應(yīng)該在什么時(shí)候用到

本文假設(shè)你已經(jīng)對(duì)指令有一定的了解了,如果沒(méi)有的話強(qiáng)烈建議你看看這篇文章AngularJS developer guide section on directives

 NG中是怎么樣處理指令的

開(kāi)始分析之前,先讓我們看看ng中是怎么樣處理指令的.

當(dāng)瀏覽器渲染一個(gè)頁(yè)面時(shí),本質(zhì)上是讀html標(biāo)識(shí),然后建立dom節(jié)點(diǎn),當(dāng)dom樹(shù)創(chuàng)建完畢之后廣播一個(gè)事件給我們.

當(dāng)你在頁(yè)面中使用script標(biāo)簽加載ng應(yīng)用程序代碼時(shí),ng監(jiān)聽(tīng)上面的dom完成事件,查找?guī)в衝g-app屬性的元素.

當(dāng)找到這樣的元素之后,ng開(kāi)始處理dom以這個(gè)元素的起點(diǎn),所以假如ng-app被添加到html元素上,則ng就會(huì)從html元素開(kāi)始處理dom.

從這個(gè)起點(diǎn)開(kāi)始,ng開(kāi)始遞歸查找所有子元素里面,符合應(yīng)用程序里定義好的指令規(guī)則.

ng怎樣處理指令其實(shí)是依賴于它定義時(shí)的對(duì)象屬性的,你可以定義一個(gè)compile或者一個(gè)link函數(shù),或者用pre-link和post-link函數(shù)來(lái)代替link.

所以這些函數(shù)的區(qū)別呢?為什么要使用它?以及什么時(shí)候使用它呢?

帶著這些問(wèn)題跟著我一步一步來(lái)解答這些迷團(tuán)吧

一段代碼

為了解釋這些函數(shù)的區(qū)別,下面我將使用一個(gè)簡(jiǎn)單易懂的例子

1.如果您有任何的問(wèn)題,請(qǐng)不要猶豫趕緊在下面加上你的評(píng)論吧.

看看下面一段html標(biāo)簽代碼

復(fù)制代碼 代碼如下:

  <level-one>
        <level-two>
            <level-three>
                Hello
            </level-three>
        </level-two>
    </level-one>

然后是一段js代碼

復(fù)制代碼 代碼如下:

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, iElem, iAttrs){
                console.log(name + ': post link');
              }
            }
          }
        }
      }
    }

    app.directive('levelOne', createDirective('levelOne'));
    app.directive('levelTwo', createDirective('levelTwo'));
    app.directive('levelThree', createDirective('levelThree'));

結(jié)果非常簡(jiǎn)單:讓ng來(lái)處理三個(gè)嵌套指令,并且每個(gè)指令都有自己的complile,pre-link,post-link函數(shù),每個(gè)函數(shù)都會(huì)在控制臺(tái)里打印一行東西來(lái)標(biāo)識(shí)自己.

這個(gè)例子能夠讓我們簡(jiǎn)單的了解到ng在處理指令時(shí),內(nèi)部的流程

代碼輸出

下面是一個(gè)在控制臺(tái)輸出結(jié)果的截圖

如果想自己試一下這個(gè)例子的話,請(qǐng)點(diǎn)擊this plnkr,然后在控制臺(tái)查看結(jié)果.

分析代碼

第一個(gè)要注意的是這些函數(shù)的調(diào)用順序:

復(fù)制代碼 代碼如下:

 // COMPILE PHASE
    // levelOne:    compile function is called
    // levelTwo:    compile function is called
    // levelThree:  compile function is called

    // PRE-LINK PHASE
    // levelOne:    pre link function is called
    // levelTwo:    pre link function is called
    // levelThree:  pre link function is called

    // POST-LINK PHASE (Notice the reverse order)
    // levelThree:  post link function is called
    // levelTwo:    post link function is called
    // levelOne:    post link function is called

這個(gè)例子清晰的顯示出了ng在link之前編譯所有的指令,然后link要又分為了pre-link與post-link階段.

注意下,compile與pre-link的執(zhí)行順序是依次執(zhí)行的,但是post-link正好相反.

所以上面已經(jīng)明確標(biāo)識(shí)出了不同的階段,但是compile與pre-link有什么區(qū)別呢,都是相同的執(zhí)行順序,為什么還要分成兩個(gè)不同的函數(shù)呢?

DOM

為了挖的更深一點(diǎn),讓我們簡(jiǎn)單的修改一下上面的代碼,它也會(huì)在各個(gè)函數(shù)里打印參數(shù)列表中的element變量

復(fù)制代碼 代碼如下:

var app = angular.module('plunker', []);

    function createDirective(name){
      return function(){
        return {
          restrict: 'E',
          compile: function(tElem, tAttrs){
            console.log(name + ': compile => ' + tElem.html());
            return {
              pre: function(scope, iElem, iAttrs){
                console.log(name + ': pre link => ' + iElem.html());
              },
              post: function(scope, iElem, iAttrs){
                console.log(name + ': post link => ' + iElem.html());
              }
            }
          }
        }
      }
    }

    app.directive('levelOne', createDirective('levelOne'));
    app.directive('levelTwo', createDirective('levelTwo'));
    app.directive('levelThree', createDirective('levelThree'));

注意下console.log里的輸出,除了輸出原始的html標(biāo)記基本沒(méi)別的改變.

這個(gè)應(yīng)該能夠加深我們對(duì)于這些函數(shù)上下文的理解.

再次運(yùn)行代碼看看

輸出

下面是一個(gè)在控制臺(tái)輸出結(jié)果的截圖

假如你還想自己運(yùn)行看看效果,可以點(diǎn)擊this plnkr,然后在控制臺(tái)里查看輸出結(jié)果.

觀察

輸出dom的結(jié)果可以暴露一些有趣的事情:dom內(nèi)容在compile與pre-link兩個(gè)函數(shù)中是不一樣的

所以發(fā)生了什么呢?

Compile

我們已經(jīng)知道當(dāng)ng發(fā)現(xiàn)dom構(gòu)建完成時(shí)就開(kāi)始處理dom.

所以當(dāng)ng在遍歷dom的時(shí)候,碰到level-one元素,從它的定義那里了解到,要執(zhí)行一些必要的函數(shù)

因?yàn)閏ompile函數(shù)定義在level-one指令的指令對(duì)象里,所以它會(huì)被調(diào)用并傳遞一個(gè)element對(duì)象作為它的參數(shù)

如果你仔細(xì)觀察,就會(huì)看到,瀏覽器創(chuàng)建這個(gè)element對(duì)象時(shí),仍然是最原始的html標(biāo)記

1.在ng中,原始dom通常用來(lái)標(biāo)識(shí)template element,所以我在定義compile函數(shù)參數(shù)時(shí)就用到了tElem名字,這個(gè)變量指向的就是template element.

一旦運(yùn)行l(wèi)evelone指令中的compile函數(shù),ng就會(huì)遞歸深度遍歷它的dom節(jié)點(diǎn),然后在level-two與level-three上面重復(fù)這些操作.

Post-link

深入了解pre-link函數(shù)之前,讓我們來(lái)看看post-link函數(shù).

2.如果你在定義指令的時(shí)候只使用了一個(gè)link函數(shù),那么ng會(huì)把這個(gè)函數(shù)當(dāng)成post-link來(lái)處理,因此我們要先討論這個(gè)函數(shù)
當(dāng)ng遍歷完所有的dom并運(yùn)行完所有的compile函數(shù)之后,就反向調(diào)用相關(guān)聯(lián)的post-link函數(shù).

dom現(xiàn)在開(kāi)始反向,并執(zhí)行post-link函數(shù),因此,在之前這種反向的調(diào)用看起來(lái)有點(diǎn)奇怪,其實(shí)這樣做是非常有意義的.

當(dāng)運(yùn)行包含子指令的指令post-link時(shí),反向的post-link規(guī)則可以保證它的子指令的post-link是已經(jīng)運(yùn)行過(guò)的.

所以,當(dāng)運(yùn)行l(wèi)evel-one指令的post-link函數(shù)的時(shí)候,我們能夠保證level-two和level-three的post-link其實(shí)都已經(jīng)運(yùn)行過(guò)了.

這就是為什么人們都認(rèn)為post-link是最安全或者默認(rèn)的寫(xiě)業(yè)務(wù)邏輯的地方.

但是為什么這里的element跟compile里的又不同呢?

一旦ng調(diào)用過(guò)指令的compile函數(shù),就會(huì)創(chuàng)建一個(gè)template element的element實(shí)例對(duì)象,并且為它提供一個(gè)scope對(duì)象,這個(gè)scope有可能是新實(shí)例,也有可能是已經(jīng)存在,可能是個(gè)子scope,也有可能是獨(dú)立的scope,這些都得依賴指令定義對(duì)象里的scope屬性值

所以當(dāng)linking發(fā)生時(shí),這個(gè)實(shí)例element以及scope對(duì)象已經(jīng)是可用的了,并且被ng作為參數(shù)傳遞到post-link函數(shù)的參數(shù)列表中去.

1.我個(gè)人總是使用iElem名稱來(lái)定義一個(gè)link函數(shù)的參數(shù),并且它是指向element實(shí)例的

所以post-link(pre-link)函數(shù)的element參數(shù)對(duì)象是一個(gè)element實(shí)例而不是一個(gè)template element.

所以上面例子里的輸出是不同的

Pre-link

當(dāng)寫(xiě)了一個(gè)post-link函數(shù),你可以保證在執(zhí)行post-link函數(shù)的時(shí)候,它的所有子級(jí)指令的post-link函數(shù)是已經(jīng)執(zhí)行過(guò)的.

在大部分的情況下,它都可以做的更好,因此通常我們都會(huì)使用它來(lái)編寫(xiě)指令代碼.

然而,ng為我們提供了一個(gè)附加的hook機(jī)制,那就是pre-link函數(shù),它能夠保證在執(zhí)行所有子指令的post-link函數(shù)之前.運(yùn)行一些別的代碼.

這句話是值得反復(fù)推敲的

pre-link函數(shù)能夠保證在element實(shí)例上以及它的所有子指令的post-link運(yùn)行之前執(zhí)行.

所以它使的post-link函數(shù)反向執(zhí)行是相當(dāng)有意義的,它自己是原始的順序執(zhí)行pre-link函數(shù)

這也意為著pre-link函數(shù)運(yùn)行在它所有子指令的pre-link函數(shù)之前,所以完整的理由就是:

一個(gè)元素的pre-link函數(shù)能夠保證是運(yùn)行在它所有的子指令的post-link與pre-link運(yùn)行之前執(zhí)行的.見(jiàn)下圖:

回顧

如果我們回頭看看上面原始的輸出,就能清楚的認(rèn)出到底發(fā)生了什么:

復(fù)制代碼 代碼如下:

    // HERE THE ELEMENTS ARE STILL THE ORIGINAL TEMPLATE ELEMENTS

    // COMPILE PHASE
    // levelOne:    compile function is called on original DOM
    // levelTwo:    compile function is called on original DOM
    // levelThree:  compile function is called on original DOM

    // AS OF HERE, THE ELEMENTS HAVE BEEN INSTANTIATED AND
    // ARE BOUND TO A SCOPE
    // (E.G. NG-REPEAT WOULD HAVE MULTIPLE INSTANCES)

    // PRE-LINK PHASE
    // levelOne:    pre link function is called on element instance
    // levelTwo:    pre link function is called on element instance
    // levelThree:  pre link function is called on element instance

    // POST-LINK PHASE (Notice the reverse order)
    // levelThree:  post link function is called on element instance
    // levelTwo:    post link function is called on element instance
    // levelOne:    post link function is called on element instance

概要

回顧上面的分析我們可以描述一下這些函數(shù)的區(qū)別以及使用情況:

Compile 函數(shù)

使用compile函數(shù)可以改變?cè)嫉膁om(template element),在ng創(chuàng)建原始dom實(shí)例以及創(chuàng)建scope實(shí)例之前.

可以應(yīng)用于當(dāng)需要生成多個(gè)element實(shí)例,只有一個(gè)template element的情況,ng-repeat就是一個(gè)最好的例子,它就在是compile函數(shù)階段改變?cè)嫉膁om生成多個(gè)原始dom節(jié)點(diǎn),然后每個(gè)又生成element實(shí)例.因?yàn)閏ompile只會(huì)運(yùn)行一次,所以當(dāng)你需要生成多個(gè)element實(shí)例的時(shí)候是可以提高性能的.

template element以及相關(guān)的屬性是做為參數(shù)傳遞給compile函數(shù)的,不過(guò)這時(shí)候scope是不能用的:

下面是函數(shù)樣子:

復(fù)制代碼 代碼如下:

/**
    * Compile function
    *
    * @param tElem - template element
    * @param tAttrs - attributes of the template element
    */
    function(tElem, tAttrs){

        // ...

    };

Pre-link 函數(shù)

使用pre-link函數(shù)可以運(yùn)行一些業(yè)務(wù)代碼在ng執(zhí)行完compile函數(shù)之后,但是在它所有子指令的post-link函數(shù)將要執(zhí)行之前.

scope對(duì)象以及element實(shí)例將會(huì)做為參數(shù)傳遞給pre-link函數(shù):

下面是函數(shù)樣子:

復(fù)制代碼 代碼如下:

/**
    * Pre-link function
    *
    * @param scope - scope associated with this istance
    * @param iElem - instance element
    * @param iAttrs - attributes of the instance element
    */
    function(scope, iElem, iAttrs){

        // ...

    };

Post-link 函數(shù)

使用post-link函數(shù)來(lái)執(zhí)行業(yè)務(wù)邏輯,在這個(gè)階段,它已經(jīng)知道它所有的子指令已經(jīng)編譯完成并且pre-link以及post-link函數(shù)已經(jīng)執(zhí)行完成.

這就是被認(rèn)為是最安全以及默認(rèn)的編寫(xiě)業(yè)務(wù)邏輯代碼的原因.

scope實(shí)例以及element實(shí)例做為參數(shù)傳遞給post-link函數(shù):

下面是函數(shù)樣子:

復(fù)制代碼 代碼如下:

/**
    * Post-link function
    *
    * @param scope - scope associated with this istance
    * @param iElem - instance element
    * @param iAttrs - attributes of the instance element
    */
    function(scope, iElem, iAttrs){

        // ...

    };

總結(jié)

現(xiàn)在你應(yīng)該對(duì)compile,pre-link,post-link這此函數(shù)之間的區(qū)別有了清晰的認(rèn)識(shí)了吧.

如果還沒(méi)有的話,并且你是一個(gè)認(rèn)真的ng開(kāi)發(fā)者,那么我強(qiáng)烈建議你重新把這篇文章讀一讀直到你了解為止

理解這些概念非常重要,能夠幫助你理解ng原生指令的工作原理,也能幫你優(yōu)化你自己的自定義指令.

如果還有問(wèn)題的話,歡迎大家在下面評(píng)論里加上你的問(wèn)題

以后還會(huì)接著分析關(guān)于指令里的其它兩個(gè)問(wèn)題:

1.指令使用transclusion屬性是怎么工作的?
2.指令的controller函數(shù)是怎么關(guān)聯(lián)的

最后,如果發(fā)現(xiàn)本文哪里有不對(duì)的,請(qǐng)及時(shí)給我發(fā)評(píng)論

謝謝!

相關(guān)文章

  • ng-alain表單使用方式詳解

    ng-alain表單使用方式詳解

    這篇文章主要介紹了ng-alain表單使用方式詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-07-07
  • Angularjs為ng-click事件傳遞參數(shù)

    Angularjs為ng-click事件傳遞參數(shù)

    這篇文章主要介紹了Angularjs為ng-click事件傳遞參數(shù)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-06-06
  • AngularJS實(shí)現(xiàn)的自定義過(guò)濾器簡(jiǎn)單示例

    AngularJS實(shí)現(xiàn)的自定義過(guò)濾器簡(jiǎn)單示例

    這篇文章主要介紹了AngularJS實(shí)現(xiàn)的自定義過(guò)濾器,結(jié)合實(shí)例形式分析了AngularJS自定義過(guò)濾器的簡(jiǎn)單定義與使用操作技巧,需要的朋友可以參考下
    2019-02-02
  • AngularJS中取消對(duì)HTML片段轉(zhuǎn)義的方法例子

    AngularJS中取消對(duì)HTML片段轉(zhuǎn)義的方法例子

    這篇文章主要介紹了AngularJS中取消對(duì)HTML片段轉(zhuǎn)義的方法例子,在一些需要顯示HTML的地方,就要取消AngularJS的轉(zhuǎn)義,本文就介紹了這種方法,需要的朋友可以參考下
    2015-01-01
  • 舉例詳解AngularJS中ngShow和ngHide的使用方法

    舉例詳解AngularJS中ngShow和ngHide的使用方法

    這篇文章主要介紹了舉例詳解AngularJS中ngShow和ngHide的使用方法,AngularJS是一款非常熱門(mén)的JavaScript框架,需要的朋友可以參考下
    2015-06-06
  • AngularJS中watch監(jiān)聽(tīng)用法分析

    AngularJS中watch監(jiān)聽(tīng)用法分析

    這篇文章主要介紹了AngularJS中watch監(jiān)聽(tīng)用法,較為詳細(xì)的分析了$watch的具體功能、相關(guān)參數(shù)用法與使用注意事項(xiàng),需要的朋友可以參考下
    2016-11-11
  • angularjs實(shí)現(xiàn)table增加tr的方法

    angularjs實(shí)現(xiàn)table增加tr的方法

    下面小編就為大家分享一篇angularjs實(shí)現(xiàn)table增加tr的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-02-02
  • 詳解Angular路由之路由守衛(wèi)

    詳解Angular路由之路由守衛(wèi)

    這篇文章主要介紹了詳解Angular路由之路由守衛(wèi),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05
  • Angular2表單自定義驗(yàn)證器的實(shí)現(xiàn)

    Angular2表單自定義驗(yàn)證器的實(shí)現(xiàn)

    本文給大家介紹angular2表單自定義驗(yàn)證器的實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),具有參考借鑒價(jià)值,感興趣的朋友一起看看吧
    2016-10-10
  • 在AngularJS中使用jQuery的zTree插件的方法

    在AngularJS中使用jQuery的zTree插件的方法

    這篇文章主要介紹了在AngularJS中使用jQuery的zTree插件的方法,Angular中集成了jqLite,但還不是完全版的jQuery,需要的朋友可以參考下
    2016-04-04

最新評(píng)論

苍山县| 吉林省| 平和县| 湖口县| 夹江县| 远安县| 沧源| 南部县| 额济纳旗| 贡嘎县| 新余市| 芦溪县| 景泰县| 桦川县| 金华市| 双牌县| 广昌县| 茶陵县| 沅陵县| 虹口区| 商都县| 青河县| 开鲁县| 武隆县| 乐昌市| 尖扎县| 沂水县| 天柱县| 义马市| 凤翔县| 荣昌县| 金寨县| 疏附县| 嘉鱼县| 尚义县| 门头沟区| 柳江县| 新兴县| 德昌县| 肥城市| 通海县|