25

我看到 ember 有一个非常好的机制,可以使用此处{{yield}}记录的机制将内容包装在组件中。

因此,要使用文档中的示例,我可以blog-post定义一个组件模板,如下所示:

<script type="text/x-handlebars" id="components/blog-post">
  <h1>{{title}}</h1>
  <div class="body">{{yield}}</div>
</script>

然后我可以blog-post使用以下表单嵌入到任何其他模板中:

{{#blog-post title=title}}
  <p class="author">by {{author}}</p>
  {{body}}
{{/blog-post}} 

我的问题是,我可以{{yield}}在组件模板中指定两个不同的插座吗?

像这样的事情可以通过Named Outlets实现,Ember.Route#renderTemplate如下所示:

车把

<div class="toolbar">{{outlet toolbar}}</div>
<div class="sidebar">{{outlet sidebar}}</div>

JavaScript

App.PostsRoute = Ember.Route.extend({
  renderTemplate: function() {
    this.render({ outlet: 'sidebar' });
  }
});

我不确定我是否可以将这条路径用于不知道哪个路由的模板将呈现它的组件。

编辑1:


为了清楚起见,我尝试将 Android Swipe for Action 模式实现为 Ember 组件。

所以,我希望这个组件的用户能够指定两个不同的模板:

  1. 普通列表项的模板,以及
  2. 检测到在 (1) 上滑动时显示的操作的模板。

我想把它变成一个组件,因为很多 javascript 都在处理触摸(开始/移动/结束)事件,同时仍然管理基于平滑触摸的列表滚动。用户将提供这两个模板,该组件将管理触摸事件和必要动画的处理。

我设法让组件以块形式工作,其中块的内容被视为 (1)。第二个模板 (2) 通过一个参数 (actionPartial下面) 指定,该参数是操作的部分模板的名称:

组件把手模板:sfa-item.handlebars

<div {{bind-attr class=":sfa-item-actions shouldRevealActions:show" }}>
    {{partial actionPartial}}
</div>

<div {{bind-attr class=":sfa-item-details isDragging:dragging shouldRevealActions:moveout"}}>
    {{yield}}
</div>

调用车把模板:

{{#each response in controller}}
    <div class="list-group-item sf-mr-item">
        {{#sfa-item actionPartial="mr-item-action"}}
            <h5>{{response.name}}</h5>
        {{/sfa-item}}
    </div>
{{/each}}

车把mr-item-action的定义如下:

mr-item-action.handlebars

<div class="sf-mr-item-action">
    <button class="btn btn-lg btn-primary" {{action 'sfaClickedAction'}}>Edit</button>
    <button class="btn btn-lg btn-primary">Delete</button>
</div>

问题是,sfaClickedAction上面用户提供的部分操作不会从组件中冒出来。第 4 段的文档中提到的事实。

所以,现在我不知道用户如何捕获他在提供的操作模板中定义的操作。组件无法捕获这些操作,因为它也不知道它们。

编辑 2


我在这里提出了一个后续问题

4

2 回答 2

29

这篇博文描述了 Ember 1.10+ 最优雅的解决方案:https ://coderwall.com/p/qkk2zq/components-with-structured-markup-in-ember-js-v1-10

在您的组件中,您将产量名称传递给{{yield}}s:

<header>
  {{yield "header"}}
</header>

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

<footer>
  {{yield "footer"}}
</footer>

当您调用您的组件时,您接受产量名称作为块参数......并使用 esleif 链!

{{#my-comp as |section|}}
  {{#if (eq section "header")}}
    My header
  {{else if (eq section "body")}}
    My body
  {{else if (eq section "footer")}}
    My footer
  {{/if}}
{{/my-comp}}

PSeq是必备的ember-truth-helpers插件中的子表达式助手。

PPS 相关 RFC:提案讨论

于 2015-05-07T16:51:29.253 回答
3

由于在一个组件中不可能有两个{{yield}}助手(组件如何知道一个{{yield}}标记在哪里停止而下一个标记从哪里开始?)您可以从不同的方向解决这个问题。

考虑嵌套组件的模式。浏览器已经非常成功地做到了这一点。<ul>以和<li>组件为例。A<ul>想要获取许多标记并将每个标记呈现为列表的成员。为了实现这一点,它会强制您将逐项标记分成<li>标签。这方面还有很多其他的例子。<table>, <tbody>, <tr>,<td>是另一个很好的例子。

我想你可能偶然发现了一个可以实现这种模式的案例。例如:

{{#sfa-item}}
  {{#first-thing}}
     ... some markup
  {{/first-thing}}

  {{#second-thing}}
    ... some other markup
  {{/second-thing}}
{{/sfa-item}}

显然first-thingsecond-thing对于您的专用组件来说,这是一个糟糕的名称,这些组件代表您想要用您的第一个和第二个模板包装的东西。你明白了。

请务必小心,因为嵌套组件无法访问外部组件中的属性。如果两者都需要,您必须将值与外部和内部组件绑定。

于 2014-04-10T15:24:51.353 回答