亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

angularjs指令中的compile與link函數詳解

2019-11-20 13:48:29
字體:
來源:轉載
供稿:網友

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

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

網上已經有很多介紹怎么使用指令的文章以及相關書籍,相互比較的話,很少有介紹compile與link的區別,更別說pre-link與post-link了.

大部分教程只是簡單的說下compile會在ng內部用到,而且建議大家只用link屬性,大部分指令的例子里都是這樣的

這是非常不幸的,因為正確的理解這些函數的區別會提高你對ng內部運行機理的理解,有助于你開發更好的自定義指令.

所以跟著我一起來看下面的內容一步步的去了解這些函數是什么以及它們應該在什么時候用到

本文假設你已經對指令有一定的了解了,如果沒有的話強烈建議你看看這篇文章AngularJS developer guide section on directives

 NG中是怎么樣處理指令的

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

當瀏覽器渲染一個頁面時,本質上是讀html標識,然后建立dom節點,當dom樹創建完畢之后廣播一個事件給我們.

當你在頁面中使用script標簽加載ng應用程序代碼時,ng監聽上面的dom完成事件,查找帶有ng-app屬性的元素.

當找到這樣的元素之后,ng開始處理dom以這個元素的起點,所以假如ng-app被添加到html元素上,則ng就會從html元素開始處理dom.

從這個起點開始,ng開始遞歸查找所有子元素里面,符合應用程序里定義好的指令規則.

ng怎樣處理指令其實是依賴于它定義時的對象屬性的,你可以定義一個compile或者一個link函數,或者用pre-link和post-link函數來代替link.

所以這些函數的區別呢?為什么要使用它?以及什么時候使用它呢?

帶著這些問題跟著我一步一步來解答這些迷團吧

一段代碼

為了解釋這些函數的區別,下面我將使用一個簡單易懂的例子

1.如果您有任何的問題,請不要猶豫趕緊在下面加上你的評論吧.

看看下面一段html標簽代碼

復制代碼 代碼如下:

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

然后是一段js代碼

復制代碼 代碼如下:

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'));

結果非常簡單:讓ng來處理三個嵌套指令,并且每個指令都有自己的complile,pre-link,post-link函數,每個函數都會在控制臺里打印一行東西來標識自己.

這個例子能夠讓我們簡單的了解到ng在處理指令時,內部的流程

代碼輸出

下面是一個在控制臺輸出結果的截圖

如果想自己試一下這個例子的話,請點擊this plnkr,然后在控制臺查看結果.

分析代碼

第一個要注意的是這些函數的調用順序:

復制代碼 代碼如下:

 // 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

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

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

所以上面已經明確標識出了不同的階段,但是compile與pre-link有什么區別呢,都是相同的執行順序,為什么還要分成兩個不同的函數呢?

DOM

為了挖的更深一點,讓我們簡單的修改一下上面的代碼,它也會在各個函數里打印參數列表中的element變量

復制代碼 代碼如下:

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標記基本沒別的改變.

這個應該能夠加深我們對于這些函數上下文的理解.

再次運行代碼看看

輸出

下面是一個在控制臺輸出結果的截圖

假如你還想自己運行看看效果,可以點擊this plnkr,然后在控制臺里查看輸出結果.

觀察

輸出dom的結果可以暴露一些有趣的事情:dom內容在compile與pre-link兩個函數中是不一樣的

所以發生了什么呢?

Compile

我們已經知道當ng發現dom構建完成時就開始處理dom.

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

因為compile函數定義在level-one指令的指令對象里,所以它會被調用并傳遞一個element對象作為它的參數

如果你仔細觀察,就會看到,瀏覽器創建這個element對象時,仍然是最原始的html標記

1.在ng中,原始dom通常用來標識template element,所以我在定義compile函數參數時就用到了tElem名字,這個變量指向的就是template element.

一旦運行levelone指令中的compile函數,ng就會遞歸深度遍歷它的dom節點,然后在level-two與level-three上面重復這些操作.

Post-link

深入了解pre-link函數之前,讓我們來看看post-link函數.

2.如果你在定義指令的時候只使用了一個link函數,那么ng會把這個函數當成post-link來處理,因此我們要先討論這個函數
當ng遍歷完所有的dom并運行完所有的compile函數之后,就反向調用相關聯的post-link函數.

dom現在開始反向,并執行post-link函數,因此,在之前這種反向的調用看起來有點奇怪,其實這樣做是非常有意義的.

當運行包含子指令的指令post-link時,反向的post-link規則可以保證它的子指令的post-link是已經運行過的.

所以,當運行level-one指令的post-link函數的時候,我們能夠保證level-two和level-three的post-link其實都已經運行過了.

這就是為什么人們都認為post-link是最安全或者默認的寫業務邏輯的地方.

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

一旦ng調用過指令的compile函數,就會創建一個template element的element實例對象,并且為它提供一個scope對象,這個scope有可能是新實例,也有可能是已經存在,可能是個子scope,也有可能是獨立的scope,這些都得依賴指令定義對象里的scope屬性值

所以當linking發生時,這個實例element以及scope對象已經是可用的了,并且被ng作為參數傳遞到post-link函數的參數列表中去.

1.我個人總是使用iElem名稱來定義一個link函數的參數,并且它是指向element實例的

所以post-link(pre-link)函數的element參數對象是一個element實例而不是一個template element.

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

Pre-link

當寫了一個post-link函數,你可以保證在執行post-link函數的時候,它的所有子級指令的post-link函數是已經執行過的.

在大部分的情況下,它都可以做的更好,因此通常我們都會使用它來編寫指令代碼.

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

這句話是值得反復推敲的

pre-link函數能夠保證在element實例上以及它的所有子指令的post-link運行之前執行.

所以它使的post-link函數反向執行是相當有意義的,它自己是原始的順序執行pre-link函數

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

一個元素的pre-link函數能夠保證是運行在它所有的子指令的post-link與pre-link運行之前執行的.見下圖:

回顧

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

復制代碼 代碼如下:

    // 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

概要

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

Compile 函數

使用compile函數可以改變原始的dom(template element),在ng創建原始dom實例以及創建scope實例之前.

可以應用于當需要生成多個element實例,只有一個template element的情況,ng-repeat就是一個最好的例子,它就在是compile函數階段改變原始的dom生成多個原始dom節點,然后每個又生成element實例.因為compile只會運行一次,所以當你需要生成多個element實例的時候是可以提高性能的.

template element以及相關的屬性是做為參數傳遞給compile函數的,不過這時候scope是不能用的:

下面是函數樣子:

復制代碼 代碼如下:

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

        // ...

    };

Pre-link 函數

使用pre-link函數可以運行一些業務代碼在ng執行完compile函數之后,但是在它所有子指令的post-link函數將要執行之前.

scope對象以及element實例將會做為參數傳遞給pre-link函數:

下面是函數樣子:

復制代碼 代碼如下:

/**
    * 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 函數

使用post-link函數來執行業務邏輯,在這個階段,它已經知道它所有的子指令已經編譯完成并且pre-link以及post-link函數已經執行完成.

這就是被認為是最安全以及默認的編寫業務邏輯代碼的原因.

scope實例以及element實例做為參數傳遞給post-link函數:

下面是函數樣子:

復制代碼 代碼如下:

/**
    * 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){

        // ...

    };

總結

現在你應該對compile,pre-link,post-link這此函數之間的區別有了清晰的認識了吧.

如果還沒有的話,并且你是一個認真的ng開發者,那么我強烈建議你重新把這篇文章讀一讀直到你了解為止

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

如果還有問題的話,歡迎大家在下面評論里加上你的問題

以后還會接著分析關于指令里的其它兩個問題:

1.指令使用transclusion屬性是怎么工作的?
2.指令的controller函數是怎么關聯的

最后,如果發現本文哪里有不對的,請及時給我發評論

謝謝!

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久视频国产精品免费视频在线| 亚洲a在线观看| 国产偷国产偷亚洲清高网站| 中文字幕日韩欧美| 色999日韩欧美国产| 国产精品色午夜在线观看| 热re99久久精品国产66热| 最近2019中文免费高清视频观看www99| 黑人与娇小精品av专区| 91在线免费看网站| 亚洲第一网中文字幕| 韩国一区二区电影| 97av在线视频| 色偷偷综合社区| 欧美精品18videosex性欧美| 欧美精品免费在线观看| 国产经典一区二区| 亚洲国产成人精品女人久久久| 欧美日韩国产精品一区二区不卡中文| 日韩av在线导航| 色偷偷亚洲男人天堂| 亚洲黄色www| 不卡av在线网站| 国产视频自拍一区| 欧美成人免费va影院高清| 日韩av高清不卡| 成人高清视频观看www| 中文字幕综合在线| 日本国产一区二区三区| 日韩在线激情视频| 一区二区三区 在线观看视| 久久成年人视频| 欧美国产第一页| 欧美乱大交做爰xxxⅹ性3| 国产欧美在线视频| 亚洲视频一区二区三区| 亚洲小视频在线观看| 最近2019免费中文字幕视频三| 亚洲欧美制服综合另类| 国产精品狠色婷| 日韩h在线观看| 国产成人精品免高潮在线观看| 韩国三级电影久久久久久| 久久精品这里热有精品| 欧美一级大胆视频| 欧美亚洲激情在线| 久久久精品一区| 欧美一级黄色网| 亚洲大胆美女视频| 国外视频精品毛片| 欧美成人精品一区二区三区| 国产国语刺激对白av不卡| 欧美激情视频在线免费观看 欧美视频免费一| 在线免费观看羞羞视频一区二区| 国产精品免费电影| 国产精品稀缺呦系列在线| 国产午夜精品久久久| 人体精品一二三区| 77777亚洲午夜久久多人| 色综合久久中文字幕综合网小说| 日韩中文字幕在线看| 日韩精品中文字幕在线观看| 国产精品视频yy9099| 精品久久久一区二区| 日韩精品极品视频免费观看| 久久69精品久久久久久国产越南| 欧美性高潮床叫视频| 日本中文字幕成人| 中文字幕日韩精品有码视频| 欧美在线www| 欧美性感美女h网站在线观看免费| 亚洲成色999久久网站| 亚洲成人精品视频| 久久久成人的性感天堂| 国产一区二区日韩精品欧美精品| 国产欧美韩国高清| 欧美视频国产精品| 国产成人精品av在线| 啪一啪鲁一鲁2019在线视频| 久久天堂电影网| 日韩中文字幕在线精品| 成人免费视频网| 韩国三级电影久久久久久| 欧美精品videosex牲欧美| 91欧美激情另类亚洲| 亚洲欧美在线一区二区| 日韩精品中文字幕在线观看| 欧美中文字幕视频在线观看| 亚洲男女自偷自拍图片另类| 97久久伊人激情网| 欧美老女人www| 国产精品精品久久久久久| 91综合免费在线| 在线观看中文字幕亚洲| 国产精品久久久久av| 青草成人免费视频| 日韩精品视频在线| 成人网在线免费观看| 亚洲免费伊人电影在线观看av| 久久国产精品久久久久久| 欧洲日本亚洲国产区| 午夜精品久久久久久99热软件| 国产日韩亚洲欧美| 亚洲男人天堂古典| 欧美激情小视频| 欧美一级免费视频| 日韩美女视频在线观看| 国产精品视频在线观看| 国产精品三级网站| 最近中文字幕mv在线一区二区三区四区| 日韩高清av一区二区三区| 久久91亚洲精品中文字幕奶水| 欧美一级电影免费在线观看| 欧美精品久久久久久久久久| 欧美日韩国产在线| 亚洲欧美日韩另类| 国产精品美女久久久免费| 欧美激情小视频| 国产视频精品一区二区三区| 亚洲直播在线一区| 亚洲一区二区三区成人在线视频精品| 欧美电影院免费观看| 欧美一级淫片videoshd| 精品国产欧美一区二区三区成人| 亚洲男人天堂视频| 亚洲图片制服诱惑| 中文字幕国产日韩| 国产午夜一区二区| 91精品视频观看| 亚洲欧美精品伊人久久| 日本精品视频在线播放| 色香阁99久久精品久久久| 日本电影亚洲天堂| 欧美极度另类性三渗透| 亚洲欧美日韩国产中文| 在线精品91av| 一本色道久久综合狠狠躁篇怎么玩| 亚洲欧美日韩在线高清直播| 久久精品亚洲热| 91av在线精品| 人九九综合九九宗合| 久久综合色影院| 国产综合久久久久| 精品视频一区在线视频| 国产成人亚洲精品| 欧美大胆a视频| 国产美女主播一区| 欧美色另类天堂2015| 欧美精品在线第一页| 姬川优奈aav一区二区| 欧美黑人性猛交| 国产精品免费一区| 亚洲最大成人网色| 成人福利网站在线观看| 欧美成人sm免费视频| 日韩亚洲欧美中文高清在线| 国产91热爆ts人妖在线| 亚洲偷熟乱区亚洲香蕉av| 精品久久久久久久久久ntr影视| 91精品久久久久久久久久另类| 国产精品丝袜久久久久久不卡| 欧日韩不卡在线视频| 色偷偷88888欧美精品久久久| 国产精品综合网站|