因为$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’页面显示