AngularJS Compile的細(xì)節(jié)

2018-07-26 17:16 更新

指令的處理過程,是 ng 的 Compile 過程的一部分,它們也是緊密聯(lián)系的。繼續(xù)深入指令的定義方法,首先就要對(duì) Compile 的過程做更細(xì)致的了解。

前面說過, ng 對(duì)頁(yè)面的處理過程:

  • 瀏覽器把 HTML 字符串解析成 DOM 結(jié)構(gòu)。
  • ng 把 DOM 結(jié)構(gòu)給 $compile ,返回一個(gè) link 函數(shù)。
  • 傳入具體的 scope 調(diào)用這個(gè) link 函數(shù)。
  • 得到處理后的 DOM ,這個(gè) DOM 處理了指令,連接了數(shù)據(jù)。

$compile 最基本的使用方式:

var link = $compile('<p>{{ text }}</p>');
var node = link($scope);
console.log(node);

上面的 $compile 和 link 調(diào)用時(shí)都有額外參數(shù)來實(shí)現(xiàn)其它功能。先看 link 函數(shù),它形如:

function(scope[, cloneAttachFn]

第二個(gè)參數(shù) cloneAttachFn 的作用是,表明是否復(fù)制原始節(jié)點(diǎn),及對(duì)復(fù)制節(jié)點(diǎn)需要做的處理,下面這個(gè)例子說明了它的作用:

<div ng-controller="TestCtrl"></div>
<div id="a">A {{ text }}</div>
<div id="b">B </div>
app.controller('TestCtrl', function($scope, $compile){
  var link = $compile($('#a'));

  //true參數(shù)表示新建一個(gè)完全隔離的scope,而不是繼承的child scope
  var scope = $scope.$new(true);
  scope.text = '12345';

  //var node = link(scope, function(){});
  var node = link(scope);

  $('#b').append(node);
});

cloneAttachFn 對(duì)節(jié)點(diǎn)的處理是有限制的,你可以添加 class ,但是不能做與數(shù)據(jù)綁定有關(guān)的其它修改(修改了也無效):

app.controller('TestCtrl', function($scope, $compile){
  var link = $compile($('#a'));
  var scope = $scope.$new(true);
  scope.text = '12345';

  var node = link(scope, function(clone_element, scope){
    clone_element.text(clone_element.text() + ' ...'); //無效
    clone_element.text('{{ text2 }}'); //無效
    clone_element.addClass('new_class');
  });

  $('#b').append(node);
});

修改無效的原因是,像 {{ text }} 這種所謂的 Interpolate 在 $compile 中已經(jīng)被處理過了,生成了相關(guān)函數(shù)(這里起作用的是 directive 中的一個(gè) postLink 函數(shù)),后面執(zhí)行 link 就是執(zhí)行了 $compile 生成的這些函數(shù)。當(dāng)然,如果你的文本沒有數(shù)據(jù)變量的引用,那修改是會(huì)有效果的。

前面在說自定義指令時(shí)說過, link 函數(shù)是由 compile 函數(shù)返回的,也就像前面說的,應(yīng)該把改變 DOM 結(jié)構(gòu)的邏輯放在 compile 函數(shù)中做。

$compile 還有兩個(gè)額外的參數(shù):

$compile(element, transclude, maxPriority);

maxPriority 是指令的權(quán)重限制,這個(gè)容易理解,后面再說。

transclude 是一個(gè)函數(shù),這個(gè)函數(shù)會(huì)傳遞給 compile 期間找到的 directive 的 compile 函數(shù)(編譯節(jié)點(diǎn)的過程中找到了指令,指令的 compile 函數(shù)會(huì)接受編譯時(shí)傳遞的 transclude 函數(shù)作為其參數(shù))。

但是在實(shí)際使用中,除我們手工在調(diào)用 $compile 之外,初始化時(shí)的根節(jié)點(diǎn) compile 是不會(huì)傳遞這個(gè)參數(shù)的。

在我們定義指令時(shí),它的 compile 函數(shù)是這個(gè)樣子的:

function compile(tElement, tAttrs, transclude) { ... }

事實(shí)上, transclude 的值,就是 directive 所在的 原始 節(jié)點(diǎn),把原始節(jié)點(diǎn)重新做了編譯之后得到的 link 函數(shù)(需要 directive 定義時(shí)使用 transclude 選項(xiàng)),后面會(huì)專門演示這個(gè)過程。所以,官方文檔上也把 transclude 函數(shù)描述成 link 函數(shù)的樣子(如果自定義的指令只用在自己手動(dòng) $compile 的環(huán)境中,那這個(gè)函數(shù)的形式是可以隨意的):

{function(angular.Scope[, cloneAttachFn]}

所以記住,定義指令時(shí), compile 函數(shù)的第三個(gè)參數(shù) transclude ,就是一個(gè) link ,裝入 scope 執(zhí)行它你就得到了一個(gè)節(jié)點(diǎn)。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)