我看到ember有一个非常好的机制,可以使用记录here的{{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}}
出口吗?
这样的事情可以通过Ember.Route#renderTemplate
中的Named Outlets来实现,例如:
车把:
<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 Pattern实现为Ember组件。
所以,我希望这个组件的用户能够指定两个不同的模板:
我想把它变成一个组件,因为相当多的javascript用于处理触摸(开始/移动/结束)事件,同时仍然管理列表的smooth touch based scrolling。用户将提供两个模板,该组件将管理触摸事件和必要动画的处理。
我设法让组件以块形式工作,块的内容被视为(1)。第二个模板(2)通过参数(下面的actionPartial
)指定,该参数是操作的partial模板的名称:
组件句柄模板: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-项-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段docs中提到的一个事实。
所以,现在我不知道用户如何捕获他在提供的操作模板中定义的操作。组件无法捕获这些操作,因为它也不知道它们。
编辑2
我提出了一个跟进问题here
答案 0 :(得分:29)
此博客文章介绍了Ember 1.10+最优雅的解决方案:https://coderwall.com/p/qkk2zq/components-with-structured-markup-in-ember-js-v1-10
在您的组件中,您将产量名称传递到qsub -V -b n -cwd /root/remotescript.sh
s:
{{yield}}
当您调用组件时,您接受yield name作为块参数...并使用esleif链!
<header>
{{yield "header"}}
</header>
<div class="body">
{{yield "body"}}
</div>
<footer>
{{yield "footer"}}
</footer>
PS {{#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}}
是来自必备ember-truth-helpers插件的子表达式助手。
PPS相关RFC:proposal,discussion。
答案 1 :(得分:6)
我为CoreView添加了一个扩展来处理这个问题(在这篇文章的最后)。扩展通过劫持_renderToBuffer方法和
来工作对于组件的模板,请使用占位符,例如
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-header'>
{{header}}
</div>
<div class='modal-body'>
{{body}}
</div>
<div class='modal-footer'>
{{footer}}
</div>
</div>
</div>
在组件的定义中,包含一个&#39;占位符&#39;标识将使用的占位符的属性:
App.BootstrapDialogComponent = Ember.Component.extend({
placeholders: [ 'header', 'body', 'footer' ],
...
});
然后,在使用组件时,请使用占位符名称,如此
{{#bootstrap-dialog}}
{{#header}}
Add Product
{{/header}}
{{#body}}
...form...
{{/body}}
{{#footer}}
<button>Save</button>
{{/footer}}
{{/bootstrap-dialog}}
以下是扩展程序中的代码:
(function() {
var _renderToBufferOriginal = Ember.CoreView.create()._renderToBuffer;
Ember.CoreView.reopen({
_renderToBuffer: function(buffer, bufferOperation) {
this.transitionTo('inBuffer', false);
var placeholders = { }
if (this.placeholders) {
this.placeholders.map(function(n) {
placeholders[n] = {
saved: Ember.Handlebars.helpers[n],
buffer: null,
}
Ember.Handlebars.helpers[n] = function(options) {
var tmp = placeholders[n].buffer = placeholders[n].buffer || Ember.RenderBuffer();
var saved = options.data.buffer;
options.data.buffer = tmp;
options.fn(options.contexts[0], options);
options.data.buffer = saved;
};
});
Ember.Handlebars.helpers['yield'].call(this, {
hash: { },
contexts: [ this.get('context') ],
types: [ "ID" ],
hashContexts: { },
hashTypes: { },
data: {
view: this,
buffer: Ember.RenderBuffer(),
isRenderData: true,
keywords: this.cloneKeywords(),
insideGroup: this.get('templateData.insideGroup'),
}
});
this.placeholders.map(function(n) {
Ember.Handlebars.helpers[n] = function(options) {
var str = ((placeholders[n].buffer)? placeholders[n].buffer.innerString(): "");
options.data.buffer.push(str);
};
});
}
var result = this._renderToBufferOriginal.apply(this, arguments);
if (this.placeholders) {
this.placeholders.map(function(n) {
Ember.Handlebars.helpers[n] = placeholders[n].saved;
});
}
return result;
},
_renderToBufferOriginal: _renderToBufferOriginal,
});
}).call(this);
答案 2 :(得分:4)
由于在一个组件中不可能有两个{{yield}}
帮助器(组件如何知道一个{{yield}}
标记停止的位置以及下一个标记何时开始?)您可能能够接近来自不同方向的这个问题。
考虑嵌套组件的模式。浏览器已经取得了巨大的成功。例如,<ul>
和<li>
组件。 <ul>
想要获取许多标记并将每个标记呈现为列表的成员。为了实现此目的,它会强制您将明细标记分隔为<li>
标记。还有许多其他例子。 <table>
,<tbody>
,<tr>
,<td>
是另一个好例子。
我想你可能偶然发现了一个可以实现这种模式的案例。例如:
{{#sfa-item}}
{{#first-thing}}
... some markup
{{/first-thing}}
{{#second-thing}}
... some other markup
{{/second-thing}}
{{/sfa-item}}
显然,first-thing
和second-thing
是您的专用组件的可怕名称,它们代表您要用第一个和第二个模板包装的内容。你明白了。
请注意,因为嵌套组件无法访问外部组件中的属性。如果两者都需要,则必须将值与外部和内部组件绑定。