function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) { var transcludeControllers; // No scope passed in: if (!isScope(scope)) {slotName = futureParentElement;futureParentElement = cloneAttachFn;cloneAttachFn = scope;scope = undefined; } if (hasElementTranscludeDirective) {transcludeControllers = elementControllers; } if (!futureParentElement) {futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element; } if (slotName) {// slotTranscludeFn can be one of three things:// * a transclude function - a filled slot// * `null` - an optional slot that was not filled// * `undefined` - a slot that was not declared (i.e. invalid)var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];if (slotTranscludeFn) { return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);} else if (isUndefined(slotTranscludeFn)) { throw $compileMinErr("noslot","No parent directive that requires a transclusion with slot name "{0}". " +"Element: {1}",slotName, startingTag($element));} } else {return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild); }}还有一个另一个函数要特别指出来,就是最后返回的 boundTranscludeFn 这个方法,下面是他的源码
function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) { function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {if (!transcludedScope) { transcludedScope = scope.$new(false, containingScope); transcludedScope.$$transcluded = true;}return transcludeFn(transcludedScope, cloneFn, { parentBoundTranscludeFn: previousBoundTranscludeFn, transcludeControllers: controllers, futureParentElement: futureParentElement}); }这两个方法到底是在做什么呢?其实就是克隆了当前指令的节点,并生成子作用域。克隆的节点由transclude定义,如果你的属性是true,则克隆的是指令模板中的ng-transclude所在的DOM节点,及其子节点。如果属性是element则克隆整个模板的节点。
angular.module("MyApp", []).directive("dropPanel", function() {return {transclude: "element",replace: true,template: "<div class="drop-panel">" +"<span ng-transclude class="111"></span>" +"</div>",link: function(scope, el, c, d, $transclude) {$transclude(function ngRepeatTransclude(clone, scope) {console.log(clone);})}}}).directive("dropPanel2", function() {return {transclude: true,replace: true,template: "<div class="drop-panel">" +"<span ng-transclude class="111"></span>" +"</div>",link: function(scope, el, c, d, $transclude) {$transclude(function ngRepeatTransclude(clone, scope) {console.log(clone);})}}})如果你觉得replace干扰了对结果的理解,你可以注释掉,然后查看控制台中打印出来的clone,你就能知道所谓transclude的属性声明为element的作用了,我们打开replace目的在于能较清楚的查看DOM节点,来获得结论,下面就是两者编译后DOM节点的区别了
看完上面的图,你可以明显的区别到两者对DOM的克隆不一样的,另外如果在声明属性为‘element"时,需要声明replace为true,才能渲染出来。我查了很多资料,最终用断点得出了我认为对的结论,断点追踪的结果是发现如果不声明replace,好像就不会执行ngTransclude指令,这点我很奇怪,正因为这样子所以导致没有成功渲染。二归根结底其实是两者的操作的DOM元素不同,在声明transclude为element时,replace为true,你取到的DOM节点是含有transclude属性的节点(子节点),而为false你拿到的并不是含有transclude属性的节点(父节点),而ng本身不对其节点进行遍历,导致没能执行ngTransclude指令
我看到一个观点觉得不错,大概意思就是:源于功能的考虑,在使用element属性的时候,一般都是起占位符的作用,你需要做的操作是对DOM的添加时候,才会用到这个克隆功能。
我觉得这个观点不错,看过很多关于ngrepeat的介绍,很多文章都说ngrepeat源码是通过$scope.$new()来生成子作用域的,实际上并不完全正确,他的确是通过$scope.$new产生子作用域的,但是这个产生功能是交给$transclude函数去做得,实际上ngrepeat的源码上是通过$transclude来生成子作用域和添加DOM节点的。与上面的观点有相似之处。
以上就是小编为大家带来的angularJs关于指令的一些冷门属性详解全部内容了,希望大家多多支持脚本之家~