因爲$compile出錯,去查了angularjs的官文,看到文末的transclude部分,我沒用過這個屬性,短短几段話跟做閱讀理解似的花了我一個多小時逐字逐句理解以圖把邏輯理順。
回頭再看看,官文還是不能細讀,既有困惑,值得記錄。
1、ng-transclude有什麼用
我們通常的自定義屬性,在沒用transclude之前的簡化配置是這樣的
//directive1 return返回
return {
restrict:'A',
scope:{},
template:dom
}
在這樣的結構下,剛開始學的時候不考慮指令原有內部元素
<div directive1>
可能存在的指令原有內部元素<br/>
</div>
結果的效果類似innerHtml重寫,寫完div內部只有dom
<div directive1>
dom
</div>
官方也解釋過不是innerHTML。
那如果開發者不想重寫其內部原有元素,怎麼辦呢?
ng-transclude剛好就是解決這個場景的需求的。讓原有元素和指令插入的模板內容共存。
2 、transclude的用法
爲了方便理解,下文如有描述爲指令時表示其真實的API類型,描述爲 標籤 / 屬性 時表示其以 標籤 / 屬性 的html形式存在
使用angular版本1.5以上,否則沒有效果,親測。
<script src="http://cdn.bootcss.com/angular.js/1.5.0/angular.js"></script>
顯示自定義指令內部原有元素
包括文本、節點,空格
必須要保證
1、transclude:true 允許顯示
2、ng-transclude指令 ,表示顯示的位置,由指令所在標籤包裹顯示
就像古代的舊人允許新人進門,新人(重寫模板)也表示願意接納舊人(原有元素),給她留了一個ng-transclude的柴房用。
這個房子要是重寫模板自己的,才能給人用。而且還能調整顯示順序。
transclude:true放在return裏,ng-transclude放在return template屬性裏,下面兩種寫法都OK
<ng-transclude> </ng-transclude>
or
<div ng-transclude> </div>
1、只要沒有transclude:true屬性,頁面上就看不到原有元素
<div directive1 now-item="{{nowItem}}" website="{{website}}">
我是指令內部原有元素<br/>
</div>
app.controller('Ctrl', ['$scope', function($scope) {
$scope.website = '1234';
}]).directive('directive1', ['$compile', function directive1Func($scope,$compile){
let dom = '插入模板的內容<br>'+
'ng-transclude標籤內容:<div ng-transclude>{{website}}</div>';
return {
scope:{
'nowItem':'@',
'mesWebsite':'@'
},
restrict:'A',
template:dom
}
}]);
顯示
2、只要有transclude:true,就算原有元素爲空,ng-transclude內部總是被原有元素(/空)覆蓋。
<div directive1 now-item="{{nowItem}}" website="{{website}}">
我是指令內部原有元素<br/>
</div>
app.controller('Ctrl', ['$scope', function($scope) {
$scope.website = '1234';
}]).directive('directive1', ['$compile', function directive1Func($scope,$compile){
let dom = '插入模板的內容<br>'+
'ng-transclude標籤內容:<div ng-transclude>{{website}}</div>';
return {
transclude:true,
scope:{
'nowItem':'@',
'mesWebsite':'@'
},
restrict:'A',
template:dom
}
}]);
顯示
3、將原有元素內容內容分成多個嵌入口,所以更改顯示順序
實現代碼
<div directive1 website="{{website}}">
<get-header>header:{{website}}</get-header> <br />
<div>內部元素1</div>
<get-footer>footer</get-footer> <br />
<div>內部元素2</div>
</div >
app.controller('Ctrl', ['$scope', function($scope) {
$scope.website = '1234';
}]).directive('directive1', ['$compile', function directive1Func($scope,$compile){
let dom = '插入模板的內容<br>'+
'ng-transclude標籤內容:<div ng-transclude="f"></div>';
return {
transclude:{
'h':'getHeader',
'f':'getFooter',
'm':'?getMiddle'
},
scope:{
'website':'@'
},
restrict:'AE',
template:function(){
return dom;
}
}
}]);
調用指令之前顯示
調用之後顯示
推薦一篇不錯的文章:
angular指令的transclude選項以及ng-transclude指令
因爲angular的版本問題導致失敗,就把這位童鞋的代碼整理到了一個html中測試,發現1.5以下不支持多個嵌入口模式(transclude:{})。【傳送門】給個地址大家一起學習,下載後用編輯器打開即可。
更新
3、更新一個transclude原有元素作用域的問題
<div>
<div ng-bind="website1"></div>
</div>
//主控制器
$scope.website1 = '11111';
頁面顯示
加上自定義指令directive1後,修改了主控制器的website1的值,結果原有元素不受影響,只有修改$parent.website1纔會有效,說明原有元素還是瘦指令父級作用域影響。
<div directive1>
<div ng-bind="website1"></div>
</div>
app.directive('directive1', ['$compile', '$interval', function directive1Func($scope,$compile){
let dom = '<input type="text"/><div ng-transclude></div>';
return {
restrict:'AE',
transclude:true,
template:dom,
link:function(scope, ele, attr){
scope.website1 = '3333'; //修改失敗
scope.$parent.website1 = '3333'; //修改成功
}
}
}]);
修改scope.website1='333’頁面顯示
修改scope.$parent.website1='333’頁面顯示