问题
The goal is to define a structure of HTML that has more than one block of content that is declared by the caller. For example, a header, body, and content. The resulting markup should be:
<header>My header</header>
<div class="body">My body</div>
<footer>My footer</footer>
The template instantiating the component would define each of the three sections, My header
, My body
, and My footer
.
With Ruby on Rails, you would use content_for :header
to capture the header content from the caller, and yield :header
to interpolate it.
Is this possible in ember.js?
回答1:
As of ember v1.10, yield accepts parameters. However handlebars doesn't yet allow for inline comparisons of variable values. By defining some properties on the component, we can get pretty close to what rails does.
Per the above example, the component's template would look like:
<header>{{yield header}}</header>
<div class="body">{{yield body}}</div>
<footer>{{yield footer}}</footer>
And the component definition would resolve the variable arguments to the yield statements:
export default Ember.Component.extend({
header: {isHeader: true},
footer: {isFooter: true},
body: {isBody: true}
});
This means that {{yield header}}
is actually yielding an object {isHeader: true}
to the consuming template. So we can use a nested if/else structure to declare the three sections like this:
{{#my-comp as |section|}}
{{#if section.isHeader}}
My header
{{else if section.isBody}}
My body
{{else if section.isFooter}}
My footer
{{/if}}
{{/my-comp}}
回答2:
The previous reply may be out-to-date.
There is an accepted RFC for this problem; the Named Templates Block API will support passing multiple blocks to a component.
As of Ember 2.3, Contextual components allows another approach to this case:
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.
Check out the 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}}
In this case, you could use the default component content or pass the specific content to any subcomponent like:
{{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.
Check out the Twiddle - full example.
来源:https://stackoverflow.com/questions/30282377/how-can-i-yield-multiple-pieces-of-content-into-an-ember-js-component-template