好吧,经过几个小时的研究,似乎最好有条件地在嵌套视图正上方的级别中包含一个命名出口。
这是因为您需要一个单一、可靠的插座来在模板中定位,并且似乎没有一种好的方法可以在运行时以编程方式命名插座。
此外,您希望定位的插座需要存在于父模板中的某个位置,该父模板位于路由器、控制器和用于呈现屏幕当前状态的呈现模板的嵌套中。如果父路由对象尚未放置出口,则您不能希望将其定位到叶节点路由中。
让我用一个例子来解释一下:
自从我最初提出问题以来,我们的 UI 已从设备列表更改为人员列表,但原理保持不变。
我有一个包含照片的人员列表,可以单击他们以在结果旁边显示更多信息。
我有一个人员模板,如下所示:
<script type="text/x-handlebars" data-template-name="people" >
<h3>People in this group</h3>
<div class="peeps">
{{#each controller}}
{{ view App.PersonView }}
{{#if selected }}
<div class='too-personal'>
{{ outlet veryPersonalDetails }}
</div>
{{/if}}
{{/each}}
</div>
</script>
还有一个类似这样的人物模板:
<script type="text/x-handlebars" data-template-name="person" >
{{#linkTo person this}}
<div data-desc="person-item" class="item">
<div class="portrait">
<img class="avatar" {{bindAttr src="gravatarUrl"}}/>
</div>
<div class="statuslabel"><span {{bindAttr class=":label statusLabel"}}>{{statusText}}</span></div>
<div class="cTitle">{{fullName}}</div>
</div>
{{/linkTo}} </script>
以及带有额外信息和编辑选项的详细信息模板
<script type="text/x-handlebars" data-template-name="person/details" >
various edit options
</script>
单击人员结果后,我的路由器会获取 URL 更新,并将详细信息模板存根到父人员模板中。我的路由器设置如下:
App.Router.map(function() {
...
this.resource('people', { path: '/people'}, function() {
this.resource('person', { path: '/:person_id' },
function() {
this.route('details');
}
);
});
});
对于单独的路线:
App.PeopleRoute = Ember.Route.extend({
model: function() {
return App.People.find();
},
setupController: function(controller, model) {
controller.set('content', model);
}
});
App.PersonRoute = Ember.Route.extend({
model: function(params) {
return App.People.peepsById[params.person_id];
},
setupController: function(controller, model) {
this._super(controller, model);
var person = model;
// this block ensures that only one person has a selected status at a time
// ignore the overly-verbose code. I'm cleaning it up tomorrow
var ls = App.People.lastSelected;
if (ls) {
ls.set('selected', false);
}
person.set('selected', true);
App.People.lastSelected = person;
controller.set('content', model);
},
renderTemplate: function() {
// person is actually stored in router 'context' rather than 'model'
// omg!
var x = this.controllerFor('personDetails').set('content', this.get('context'));
this.render('person/details', { // render person/details
into:'people', // into the people template
outlet: "veryPersonalDetails", // at the veryPersonalDetails outlet
controller: x // using the personDetails controller for rendering
});
// additional rendering in sidebar outlet for testing
this.render('person/details',{
into:'people',
outlet: "personDetails",
controller: x
});
console.log("@@@ we did it!");
}
});
我最初尝试在 PersonView 中拥有出口,但这行不通,因为我的人员模板实际上是在人员路线中呈现的。当应用程序到达人员路线时,控制器已经渲染了列表中的所有人员。我想要瞄准的那个人早已过去了。
通过让路由充当父模板和所需子模板之间的中介,我能够实现这一点。
最后,关于是否在模板中显式声明嵌套视图,或仅使用出口的问题,我认为出口要干净得多。虽然此解决方案涉及一些围绕路线的工作,但它比拥有过于复杂的模板对象要好得多。现在,我希望能够实现任意复杂的模板嵌套,而无需触及除渲染中涉及的路线之外的任何内容。
此外,该解决方案消除了未使用的插座的开销。我相信你应该只拥有你打算使用的插座,而不是在“dom”上乱扔一堆空容器对象。