@frank-shaw
2016-09-24T17:56:50.000000Z
字数 2369
阅读 2078
angular.js
参考文章:
1. http://teropa.info/blog/2015/06/09/transclusion.html
2. http://jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives-part-2-transclusion/
3. https://docs.angularjs.org/guide/directive
假设我们定义了一个自定义指令myTest,而且是Element类型的,那么我们就会有基本的用法:<my-test></my-test>
,那么如果我想在其中添加自己的内容,像这样:<my-test>我是要显示的内容</my-test>
,或者这样:
<my-test>
<span>水杯</span>
</my-test>
这个时候,如何把这其中的内容封装到DOM中呢?这个时候就需要用到transclude选项了。直接上例子(参考官网:https://docs.angularjs.org/guide/directive):
//script.js
(function(angular) {
'use strict';
angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {
//...
}])
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
templateUrl: 'my-dialog.html'
};
});
})(window.angular);
//index.html
<body ng-app="docsTransclusionExample">
<div ng-controller="Controller">
<my-dialog>
<span>Check out the contents</span>
</my-dialog>
</div>
</body>
//my-dialog.html
<div>This is me</div>
<div ng-transclude></div>
上面函数的功能很简单,index.html中自定义指令为myDialog,在script.js中设置该指令的模板URL为my-dialog.html
。由于此时的自定义指令中包含内容Check out the contents
,所得到的DOM结构会是这样的:
<body ng-app="docsTransclusionExample">
<div ng-controller="Controller">
<div>This is me</div>
<span>Check out the contents</span>
</div>
</body>
这个时候,我们就可以知道transclude的作用了。其中,属性ng-transclude表明的是具体插入的位置。
更多的,实际上transclude选项可选参数有true
、 element
。我们只分析参数设置为true
的情况。
作用域一直是一个让人纠结的难点。对上面的例子做一点修改,变成下面的例子,预测一下输出是什么:
//script.js
(function(angular) {
'use strict';
angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) {
$scope.name = "Frank";
}])
.directive('myDialog', function() {
return {
restrict: 'E',
transclude: true,
scope:{},
templateUrl: 'my-dialog.html',
link: function(scope) {
scope.name = "shaw";
}
};
});
})(window.angular);
//index.html
<body ng-app="docsTransclusionExample">
<div ng-controller="Controller">
<my-dialog>
<span>Check out the contents, {{name}}</span>
</my-dialog>
</div>
</body>
//my-dialog.html
<div>Hello, {{name}}</div>
<div ng-transclude></div>
它的输出是这样的:
这是否和你想象中的一样呢?
我们来分析一下:在自定义指令中,我们已经设置了scope:{}
,这意味着已经将自定义指令创建的子作用域与父作用域隔离开来了(你应该知道这个)。但是为什么还是会输出Frank呢?而且,同样是my-dialog.html中的文件,<div>Hello, {{name}}</div>
的输出是Hello, shaw
,而<div ng-transclude></div>
输出的却是Check out the contents, Frank
???
实际上,transclude选项会创建自己的作用域,而创建的位置就是属性ng-transclude所在的位置及其内部元素。而这个transclude作用域继承的是自定义指令(我们这里是my-dialog)外的作用域。借鉴下图即可理解(忽视左侧的具体HTML内容):
那么这个时候,再回到刚刚的例子中。也就可以理解为什么这么输出了。