AngularJS:指令控制器中的$ transclude local和链接函数中的transclude参数之间有区别吗?

时间:2014-03-22 22:16:46

标签: angularjs angularjs-directive

我实现了一个将多个子内容片段转换为模板的指令。它有效,但似乎比我见过的大多数例子都简单,并提出了一些关于如何进行翻译的问题。

这是指令:

module.directive('myTransclude', function() {
  return {
    restrict: 'A',
    transclude: true,
    replace: true,
    scope: true,
    template: '<div style="border: 1px solid {{color}}"><div class="my-transclude-title"></div><div class="my-transclude-body"></div></div>',
    link: function(scope, element, attrs, controller, transclude) {
      // just to check transcluded scope
      scope.color = "red";
      transclude(scope, function(clone, scope) {
        Array.prototype.forEach.call(clone, function(node) {
          if (! node.tagName) {
            return;
          }
          // look for a placeholder node in the template that matches the tag in the multi-transcluded content
          var placeholder = element[0].querySelector('.' + node.tagName.toLowerCase());
          if (! placeholder) {
            return;
          }
          // insert the transcluded content
          placeholder.appendChild(node);
        });
      });
    }
  }
});

以下是示例用法:

<div ng-controller="AppController">
    <div my-transclude>
        <my-transclude-title> <strong ng-bind="title"></strong>

        </my-transclude-title>
        <my-transclude-body>My name is {{name}} and I've been transcluded!</my-transclude-body>
    </div>
</div>

您可以在this fiddle中看到它。

请注意以下几点:

  1. 它通过元素类将片段匹配到模板占位符,而不是显式定义的子指令。有什么理由这样或那样做吗?
  2. 与我见过的很多例子不同,它没有明确地在子片段上使用$ compile服务。似乎Angular正在编译片段后进行翻译,至少在这个简单的情况下。这总是正确的吗?
  3. 它使用链接函数的(几乎没有记录的)transclude参数,而不是将$ transclude local注入到controller指令中的其他(几乎没有文档记录)方法。在听到如此多的告诫不操纵控制器中的DOM之后,控制器方法看起来像是一个奇怪的构造,在链接函数中处理这种情况感觉更自然。但是,我尝试了这种方式,似乎工作相同。两者之间有什么区别吗?
  4. 感谢。

    编辑:为了部分回答问题#2,我发现你需要显式编译未应用指令的模板克隆的被盗内容。请参阅此处的行为差异:http://jsfiddle.net/4tSqr/3/

2 个答案:

答案 0 :(得分:2)

要回答关于指令控制器链接功能中$ transclude功能之间差异的问题,首先我们需要了解可以通过指令访问$ transclude函数编译控制器链接功能。

更新:根据1.4 Angular文档,编译(transclude)已被弃用!因此,只能在您的指令控制器链接功能中访问转码功能。 (参见detail explanation

的官方文档

编译阶段使用$ transclude与控制器中的$ transclude和链接阶段时,由于编译阶段的原因,存在很大差异,您无法访问$ scope而不是在控制器和链接函数中使用$ scope(控制器)和范围(链接)可访问。话虽如此,在指令控制器与链接中使用$ transclude的唯一差异执行顺序。对于多个嵌套指令,在链接阶段使用$ transclude而不是在控制器中使用它是相对安全的。

订单如下:

  1. parentDirectiveCompile - &gt; childDirectiveCompile(指令编译)

  2. parentDirectiveControllerPre,parentDirectiveControllerPost - &gt; childDirectiveControllerPre,childDirectiveControllerPost(指令控制器)

  3. childLinkFunction - &gt; parentLinkFunction
  4. 注意childLinkFunction如何在parentLinkFunction之前首先执行? (执行顺序)

    有用资源

    希望这个答案对您有所帮助!

答案 1 :(得分:0)

经过一番调查后发现:

在Angular 1.20发布之后,具有隔离范围的已编译指令的预先存在的子节点将不再继承新隔离范围,因为它们已被分配给父范围。所以...使用属性ng-transclude的内置转换方法在这种情况下只会将模板转换到所需的位置,但不会将预先存在的html转换到此位置。这意味着如果您有一个带有隔离范围的指令,并且您希望将已经存在的html编译到新的隔离范围,则需要在指令内部使用transclude链接器函数。

您可以在此处查看此问题的工作案例ui-codemirror placed within custom directives fails without an error