了解指令定义的嵌入选项?

Posted

技术标签:

【中文标题】了解指令定义的嵌入选项?【英文标题】:Understanding the transclude option of directive definition? 【发布时间】:2013-02-24 03:10:56 【问题描述】:

我认为这是我用 angularjs 的指令最难理解的概念之一。

来自http://docs.angularjs.org/guide/directive 的文件说:

transclude - 编译元素的内容并使其可用于指令。通常与 ngTransclude 一起使用。嵌入的优点是链接函数接收一个预先绑定到正确范围的嵌入函数。在典型设置中,小部件会创建一个隔离范围,但嵌入不是子范围,而是隔离范围的兄弟。这使得小部件可以拥有私有状态,并且嵌入可以绑定到父(预隔离)范围。

true - 嵌入指令的内容。 'element' - 嵌入整个元素,包括以较低优先级定义的任何指令。

上面写着transclude,通常与ngTransclude 一起使用。但是ngTransclude 文档中的示例根本不使用ngTransclude 指令。

我想要一些很好的例子来帮助我理解这一点。为什么我们需要它?它解决了什么问题?怎么用?

【问题讨论】:

仅供参考...链接至少现在有效 【参考方案1】:

考虑一个元素中名为 myDirective 的指令,并且该元素包含一些其他内容,比方说:

<div my-directive>
    <button>some button</button>
    <a href="#">and a link</a>
</div>

如果myDirective 正在使用模板,您会看到&lt;div my-directive&gt; 的内容将被您的指令模板替换。所以有:

app.directive('myDirective', function()
    return
        template: '<div class="something"> This is my directive content</div>'
    
);

将导致此渲染:

<div class="something"> This is my directive content</div> 

请注意,您的原始元素 &lt;div my-directive&gt; 将丢失(或者更好地说,被替换)的内容。所以,跟这些小伙伴说再见吧:

<button>some button</button>
<a href="#">and a link</a>

那么,如果您想在 DOM 中保留您的 &lt;button&gt;...&lt;a href&gt;... 怎么办?你需要一种叫做嵌入的东西。这个概念非常简单:将内容从一个地方包含到另一个地方。所以现在你的指令看起来像这样:

app.directive('myDirective', function()
    return
        transclude: true,
        template: '<div class="something"> This is my directive content</div> <ng-transclude></ng-transclude>'
    
);

这将呈现:

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>. 

总之,当你想在使用指令时保留元素的内容时,基本上可以使用 transclude。

我的代码示例是here。 你也可以从观看this 中受益。

【讨论】:

似乎他们已经稍微改变了功能。至少在版本 >= 1.2.9 中。模板中的内容不会添加到呈现的内容中。请参阅下面@TechExplorer 的答案 一个非常非常好的答案。远超常人。你有很好的例子,你的“这是我的指令内容”使它在渲染版本中很容易阅读。我不明白为什么 Angular 必须使用复杂的术语和概念,然后不包含像您这样易于理解的示例。 +2 有谁知道嵌入的内容是否可以引用指令的隔离范围字段?它上面说嵌入是隔离范围的兄弟,而不是孩子......所以我假设它不能 - 但想知道是否有人可以确认或让我知道是否可能 @UladzimirHavenchyk 谢谢,他们把视频移到了其他地方。我相应地修复了链接。 @odiseo,你能不能像这样用简单易懂的英语写下所有的 Angular 文档! + 多个 1。【参考方案2】:

我认为在新版本的 AngularJS 中提及上述行为的变化很重要。我花了一个小时尝试使用 Angular 1.2.10 实现上述结果。

带有 ng-transclude 的元素的内容不会被追加,而是被完全替换。

所以在上面的例子中,你可以用“transclude”实现:

<div class="something">
    <button>some button</button>
    <a href="#">and a link</a>
</div>

而不是

<div class="something"> This is my directive content
    <button>some button</button>
    <a href="#">and a link</a>
</div>

谢谢。

【讨论】:

有关 Angular 1.2 中更改的行为的更多信息,请参阅更改 eed299a。【参考方案3】:

TechExplorer 说的是真的,但是您可以通过在模板中包含一个带有 ng-transclude 属性的简单容器标签(如 div 或 span)来同时拥有这两种内容。这意味着您模板中的以下代码应包含所有内容

<div class="something"> This is my directive content <div class="something" ng-transclude></div></div>

【讨论】:

这是其他答案中缺少的关键信息 这个答案增加了很多信息。 ng-transclude 是充当占位符的属性,其中将放置已嵌入的内容。【参考方案4】:

来自维基:

“在计算机科学中,嵌入是包含部分或全部 通过引用将电子文档转换为一个或多个其他文档。”

我想为transclusion添加另一个用途,那就是它改变了父子指令的编译和链接函数的执行顺序。当您想在父 DOM 之前编译子 DOM 时,这可能很有用,因为父 DOM 可能取决于子 DOM。这篇文章更深入,也很清楚!

http://www.jvandemo.com/the-nitty-gritty-of-compile-and-link-functions-inside-angularjs-directives-part-2-transclusion/

【讨论】:

【参考方案5】:

Updated AngularJS 1.6.6 documentation 现在有了更好的解释。

Transclude 用于创建包裹其他元素的指令

有时希望能够传入整个模板而不是字符串或对象。假设我们要创建一个“对话框”组件。对话框应该能够包装任意内容。

为此,我们需要使用 transclude 选项。请参考以下示例。


script.js

angular.module('docsTransclusionExample', [])
.controller('Controller', ['$scope', function($scope) 
  $scope.name = 'Tobias';
])
.directive('myDialog', function() 
  return 
    restrict: 'E',
    transclude: true,
    scope: ,
    templateUrl: 'my-dialog.html',
    link: function(scope) 
      scope.name = 'Jeff';
    
  ;
);

index.html

<div ng-controller="Controller">
  <my-dialog>Check out the contents, name!</my-dialog>
</div>

我的对话框.html

<div class="alert" ng-transclude></div>

编译输出

<div ng-controller="Controller" class="ng-scope">
  <my-dialog class="ng-isolate-scope"><div class="alert" ng-transclude="">Check out the contents, Tobias!</div></my-dialog>
</div>

Transclude 使带有此选项的指令的内容可以访问指令外部而不是内部的范围。

这在前面的示例中进行了说明。请注意,我们在 script.js 中添加了一个将 name 重新定义为 Jeff 的链接函数。通常,我们希望 name 是 Jeff。但是,我们在此示例中看到 name 绑定仍然是 Tobias。

最佳实践:仅当您要创建包装任意内容的指令时才使用transclude: true

【讨论】:

【参考方案6】:

transclude:true 表示将指令中定义的所有元素添加到指令的模板元素中。

如果 transclude:false 则这些元素不包含在指令的最终 html 中,仅呈现指令模板。

transclude:element 表示您的指令模板不只使用定义的元素 在您的指令中呈现为 html。

当你定义你的指令时,它应该限制为 E,当你在页面上添加它时

<my-directive><elements><my-directive>
<elements> is like <p>gratitude</p>
what i am talking about.

【讨论】:

以上是关于了解指令定义的嵌入选项?的主要内容,如果未能解决你的问题,请参考以下文章

将选项从控制器传递到嵌入式 Symfony 表单时,选项不存在错误

Vue自定义指令

嵌入式:ARM指令集分类及编码

使用带有自定义对齐分配器实现的最新 g++ 使用 SSE 和 -O3 选项编译时出现非法指令(核心转储)

Vue自定义指令

AngularJS学习笔记之directive——scope选项与绑定策略