误点:directive
里面的 transclude
是 directive
scope 的一个子 scope
angular.module('app', []).controller('ctrl', function ($scope) {
$scope.data = 'controller data';
$scope.hello = 'controller hello world';
}).directive('test', function () {
return {
restrict: 'E',
template: '<div>{{data}}<div ng-transclude></div></div>',
transclude: true,
link: function (scope) {
scope.data = 'directive data';
scope.hello = 'directive hello';
},
scope: {
data: '='
}
};
});
<body ng-controller="ctrl">
<test data="data">
<span>{{data}}</span>
<span>{{hello}}</span>
</test>
</body>
结果:
若
transclude
内的 scope 为 directive 的子 scope 的话,上图就应该都是 directive 的内容,而不会出现 controller hello world
这个数据。实际上,
transclude
内部的 scope 为 controller 的一个非独立子 scope,而非 directive 的。因此,在 transclude
里面所拿到的数据均为 controller 的数据,而非 directive 的。所以例子中,
{{hello}}
则为 controller 的数据。而 {{data}}
的情况又有所不同了。在这个例子中,directive 作为一个独立的 scope 而存在,而且将
data
作为双向数据绑定与 controller 做了一个绑定,因此,实际上在执行 directive 的代码之后,controller 里面的 $scope.data
就与 directive 里面的 scope.data
同步了,因此为 directive data
。directive 里面 link
方法的第五个参数:transclude
directive 里面的
transclude
默认执行情况如上所示,它会从 controller 里面产生一个新的非独立子 scope 。除此之外,也可以利用 directive 的 link
方法的 transclude
来操纵 transclude
的表现。link: function (scope, element, attr, ctrl, transcludeFn) {
}
link
方法有固定的5个参数,如上所示。其中,transcludeFn
接受一个函数,以及可选的 scope 作为第一个参数:transcludeFn(scope.$parent, function (clone, scope) {
});
// or
transcludeFn(function (clone, scope) {
});
其中,第一个 scope 参数即为传递给 transclude HTML 的 scope。第二个回调函数即表示对 transclude 的操作。它有两个参数,第一个是 transclude 的 HTML 的拷贝,另外一个则是作用于该 HTML 的 scope。如果有显式地传递 scope 给
transcludeFn
,则该参数为传递进来的 scope ,否则为默认的从 controller 创建的一个新的 子 scope 。传递
scope.$parent
给 transcludeFn
这种做法与默认情况下 transclude
的做法最大的区别就是,手动传递进来的 scope 为 controller 的 scope 本身,而默认的 scope 是创建一个 controller 的一个 子 scope 。