Transclude好像并不是一個(gè)英語(yǔ)單詞,有道詞典沒(méi)有,百度翻譯的意思是嵌入的意思。transclude
在angularjs的自定義directive中是比較常見(jiàn)的一個(gè)東西,所以非常有必要了解一下。
我們首先看下官方api對(duì)ng-transclude
的解釋:
Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion. Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
官方例子:
<div ng-controller="ctrl">
<input ng-model="title"></br>
<textarea ng-model="text"</textarea></br>
<pane title="{{title}}"</pane>
</div>
這里的pane
是一個(gè)自定義directive,標(biāo)簽里還有一個(gè)表達(dá)式,這個(gè)指令的目的是顯示input中輸入title,和textarea中輸入的text,當(dāng)然是按照一定的dom結(jié)構(gòu)顯示??聪聀ane是如何實(shí)現(xiàn):
app.directive('pane', function() {
return {
restrict: 'E',
transclude: true,
scope: {
title:'@'
},
template:
'<div style="border: 1px solid black;">' +
'<div style="background-color: gray">{{title}}</div>' +
'<div ng-transclude></div>' +
'</div>'
};
});
首先是我們想把<pane title="AngularJS的ngTransclude"></pane>
中AngularJS的ngTransclude
和變量的內(nèi)容封裝到我們的dom結(jié)構(gòu)中,
AngularJS的ngTransclude
可以通過(guò)結(jié)構(gòu)scope: { title:'@' }
取得,但是我們想要保留<pane></pane>
標(biāo)簽里的東西(有可能會(huì)是很多的表達(dá)式和dom結(jié)構(gòu)),那就需要今天的主角transclude
了。
這個(gè)例子的結(jié)果生成的dom結(jié)構(gòu)是這樣的:
<div style="border: 1px solid black;">
<div style="background-color: gray">我是標(biāo)題</div>
我是內(nèi)容
</div>
有個(gè)這樣結(jié)果我想你就看明白了。原來(lái)模板中的<div ng-transclude></div>
最后會(huì)被<pane></pane>
標(biāo)簽里的表達(dá)式內(nèi)容所替換。這是就是transclude的用途。
我們回過(guò)頭再來(lái)看ng-transclude的定義:
這個(gè)例子夠簡(jiǎn)單,這也是最基礎(chǔ)的用法,我們?cè)賮?lái)看下高級(jí)一點(diǎn)的用法。我們對(duì)上面的例子進(jìn)行擴(kuò)充,加上了類型和時(shí)間:
<div ng-controller="Ctrl">
<input ng-model="title"><br>
<input ng-model="type"><br>
<input ng-model="time"><br>
<textarea ng-model="text"></textarea> <br/>
<pane title="{{title}}">
<span class="time">time</p>
<p class="type">{{type}}<p>
<p class="content">{{text}}<p>
</pane>
</div>
最終的目的是這樣的:
<div style="border: 1px solid black;">
<div style="background-color: gray">
我是標(biāo)題<span class="time">我是時(shí)間</span>
</div>
<p class="type">我是分類</p>
<p class="content">我是內(nèi)容</p>
</div>
光一個(gè)ng-transclude是不行的,當(dāng)然你也可以像title那樣傳參,但現(xiàn)在是在學(xué)習(xí)transclude,沒(méi)有transclude還學(xué)個(gè)毛啊。我們有兩種方法可以實(shí)現(xiàn)這個(gè)目的。
先看pane的directive代碼:
app.directive('pane', function() {
return {
restrict: 'EA',
template:
'<div style="border: 1px solid black;">' +
'<div class="title" style="background-olor: gray">{{title}}</div>' +
'</div>',
replace: true,
transclude: true,
compile: function(element, attrs, transcludeFn) {
return function (scope, element, attrs) {
transcludeFn(scope, function(clone) {
var title= element.find('title');
var time = clone.find('.time');
var type = clone.find('.type');
var text= clone.find('.content');
title.append(time);
element.append(type);
element.append(text)
});
};
}
};
});
transcludeFn
是一個(gè)function:transcludeFn(scope, function(clone){})
作用域和嵌入包含的內(nèi)容,clone嵌入的內(nèi)容是被jquery封裝過(guò)的,有了它,我們就可以做任何想要做的dom操作了。
先上代碼:
app.directive('pane', function() {
return {
restrict: 'EA',
template:
'<div style="border: 1px solid black;">' +
'<div class="title" style="background-olor: gray">{{title}}</div>' +
'</div>',
replace: true,
transclude: true,
controller: [
'$scope', '$element', '$transclude',
function ($scope, $element, $transclude) {
$transclude(function(clone, scope) {
var title= element.find('title');
var time = clone.find('.time');
var type = clone.find('.type');
var text= clone.find('.content');
title.append(time);
element.append(type);
element.append(text)
});
}
]
};
});
換湯不換藥,其實(shí)就是$transclude
,transcludeFn
這兩個(gè)函數(shù)執(zhí)行的地方不同。里面是一模一樣的。
還有一個(gè)需要說(shuō)明的是transclude的作用域的問(wèn)題。
在官方文檔中提到過(guò)deretive的作用域是單獨(dú)的,transclude
也創(chuàng)建了一個(gè)單獨(dú)的作用域,而且與derectvie的作用域是平行的,還是拿上面的例子來(lái)說(shuō)。
<div ng-controller="Ctrl">...</div>
首先controller Ctrl會(huì)創(chuàng)建一個(gè)作用域scope1,derective Pane會(huì)在scope1下面創(chuàng)建一個(gè)scope2,scope1 包含 scope2,tranclude又會(huì)在scope1下面創(chuàng)建一個(gè)scope3,scope1也包含scope3,scope2和scope3是兄弟關(guān)系,平行的兩個(gè)子作用域。
好,我們可以來(lái)驗(yàn)證一下:
在controller中加日志,
function Ctrl($scope) {
$scope.title = 'Lorem Ipsum';
$scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
console.log('scope1', $scope);
}
在derective中添加日志,
app.directive('pane', function() {
return {
restrict: 'EA',
template:
'<div style="border: 1px solid black;">' +
'<div class="title" style="background-olor: gray">{{title}}</div>' +
'</div>',
replace: true,
transclude: true,
controller: [
'$scope', '$element', '$transclude',
function ($scope, $element, $transclude) {
console.log('scope2', $scope)
$transclude(function(clone, scope) {
console.log('scope3', scope);
var title= element.find('title');
var time = clone.find('.time');
var type = clone.find('.type');
var text= clone.find('.content');
title.append(time);
element.append(type);
element.append(text)
});
}
],
};
});
在控制臺(tái)可以看到,
scope1 a {$id: "003", this: a, $listeners: Object, $parent: e, $childTail: null…}
scope2 e {$id: "004", $childTail: null, $childHead: null, $prevSibling: null, $nextSibling: null…}
scope3 a {$id: "005", this: a, $listeners: Object, $parent: a, $childTail: null…}
點(diǎn)開(kāi)scope2
和scope3
,就能看到$paren
t的Id為003,這就印證了我們的觀點(diǎn)。
更多建議: