如何将多个内容生成 ember.js 组件模板?

How can I yield multiple pieces of content into an ember.js component template?

目标是定义一个 HTML 的结构,其中包含调用方声明的多个内容块。例如,header、body和内容。生成的标记应为:

<header>My header</header>
<div class="body">My body</div>
<footer>My footer</footer>

实例化组件的模板将定义三个部分中的每一个,My headerMy bodyMy footer

在 Rails 上使用 Ruby,您将使用 content_for :header 从调用方捕获 header 内容,并使用 yield :header 对其进行插值。

这在 ember.js 中可行吗?

从 ember v1.10 开始,yield 接受参数。然而 handlebars 还不允许对变量值进行内联比较。通过在组件上定义一些属性,我们可以非常接近 rails 所做的事情。

根据上面的示例,组件的模板如下所示:

<header>{{yield header}}</header>
<div class="body">{{yield body}}</div>
<footer>{{yield footer}}</footer>

并且组件定义会将变量参数解析为 yield 语句:

export default Ember.Component.extend({
  header: {isHeader: true},
  footer: {isFooter: true},
  body:   {isBody: true}
});

这意味着 {{yield header}} 实际上正在向消费模板生成一个对象 {isHeader: true}。所以我们可以使用嵌套的 if/else 结构来声明三个部分,如下所示:

{{#my-comp as |section|}}
  {{#if section.isHeader}}
    My header
  {{else if section.isBody}}
    My body
  {{else if section.isFooter}}
    My footer
  {{/if}}
{{/my-comp}}

之前的回复可能已经过时了。

这个问题有一个公认的 RFC; Named Templates Block API 将支持将多个块传递给一个组件。

从 Ember 2.3 开始,Contextual components 允许另一种方法处理这种情况:

Split your component into multiple subcomponents and pass the subcomponents back to the component as block parameters; this setup allows to set the content of each subcomponent block.

查看 Twiddle - full example

// my-component.js

{{yield (hash
   header = (component 'my-header')
   content = (component 'my-content')
   footer = (component 'my-footer')
)}}
{{#unless hasBlock}}
   {{my-header}}
   {{my-content}}
   {{my-footer}}    
{{/unless}}

// my-{header/content/footer}.js

{{#if hasBlock}}
   {{yield}}
{{else}}
   Default xxxxx
{{/if}}

在这种情况下,您可以使用默认组件内容或将特定内容传递给任何子组件,例如:

{{my-component}}



{{#my-component as |f|}}
  {{f.header}}
  {{#f.content}}
    Custom content
  {{/f.content}}
  {{f.footer}}
{{/my-component}}


{{#my-component as |f|}}
  {{#f.header}}
     Custom header
  {{/f.header}}
  {{#f.content}}
     Custom content
  {{/f.content}}
  {{#f.footer}}
     Custom footer
  {{/f.footer}}
{{/my-component}}

This solution does not force the component API/structure, then the component could be wrongly used if a subcomponent is omitted, added multiple times, or have the wrong order, in these cases the component will generate an undesired content.

查看 Twiddle - full example