我刚刚开始使用 Ember.js,似乎很有希望的一件事是多个插座将多个模板混合在一起以产生复杂但模块化的布局的想法。
不过,我无法让它工作。几个月前(2012 年年中)似乎有很多问题、答案和示例,但在 3 月到 1.0 时,他们最近(2012 年 12 月/2013 年 1 月)将路由器重写为“v2”API。这些文档擅长他们所描述的内容,但省略了很多大背景,而且我还没有找到一个端到端的例子。
这是我读过的:
- 路由指南下的所有内容(最新,但并不详尽)
- “出口”模板助手 api 参考(这可能已经过时了?我每次尝试调用都
controller.connectOutlet()
失败了Uncaught TypeError: Object <(generated animals.cats controller):ember170> has no method 'connectOutlet'
. - Ember.js 路由器 API v2的公告。特别是底部的一对评论(多个网点的问答)。是的,这个要点被标记为“警告;过时;有关最新信息,请参阅路由指南”。但是当前的路由指南似乎并没有完全描述这种行为。指南的渲染模板部分展示了如何渲染到已经存在的不同插座(我可以让它工作),但我不知道如何连接额外的插座或实例化额外的模板。
什么对我有用:
- 设置嵌套路由(嗯,嵌套资源;你不能嵌套路由;但你可以为嵌套资源自定义路由),以及嵌套模板和根据路由自动实例化的出口。
我无法弄清楚如何完成:
- 手动实例化模板并将它们连接到插座。如果您想使用多个出口,或者如果您想要构建与您的路线不同的出口/模板关系,这似乎是必要的。(下面会有一个例子。基本上我想要做的是使用模板作为混合,我可以将它嵌入到任何我想要的地方。)
对我来说似乎很有希望但失败的事情是
- 覆盖路由的控制器(使用扩展路由
App.WhateverRoute = Ember.Route.extend()
,提供我自己的setupController
方法)并controller.connectOutlet
在此处调用。如上所述,这失败了;传递给此方法的控制器对象没有connectOutlet
方法。
示例(此处为 jsFiddle,或以下为自包含 html 文档,其中嵌入了 CSS 和脚本并从 https 链接加载 Ember 和依赖项,因此您应该能够保存到本地文件并在浏览器中打开如果您想试试):
<!DOCTYPE html>
<html lang="en">
<head>
<title>Ember.js Router Example</title>
<style>
.outlet {
border: 1px solid black;
padding: 5px;
}
</style>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="https://raw.github.com/wycats/handlebars.js/1.0.rc.2/dist/handlebars.js"></script>
<script src="https://raw.github.com/emberjs/ember.js/release-builds/ember-1.0.0-pre.4.js"></script>
<script type="text/x-handlebars" data-template-name="index">
<p>Root index template. You should not see this because we redirect App.IndexRoute elsewhere.</p>
</script>
<script type="text/x-handlebars" data-template-name="about">
<p>About this demo.</p>
</script>
<script type="text/x-handlebars" data-template-name="guide">
<p>Guide to this demo.</p>
</script>
<script type="text/x-handlebars" data-template-name="animals">
<p>Animals. You have selected:</p>
<div class='outlet'>{{ outlet }}</div>
</script>
<script type="text/x-handlebars" data-template-name="animals/index">
<!-- you will not see this unless you disable App.AnimalsIndexRoute redirect. -->
<p>No animal selected.</p>
</script>
<script type="text/x-handlebars" data-template-name="animals/cats">
<p>Cat. I can meow. Like all animals, I
<span class='outlet'>{{ outlet }}</span>
</p>
</script>
<script type="text/x-handlebars" data-template-name="animals/dogs">
<p>Dog. I can bark. Like all animals, I
<span class='outlet'>{{ outlet }}</span>
</p>
</script>
<script type="text/x-handlebars" data-template-name="animal_mixin">
<p>am alive.</p>
</script>
<script type="text/x-handlebars" data-template-name="application">
<div class="container">
<p>
Select contents for my outlet:
{{#linkTo "index"}}/ (root){{/linkTo}}
{{#linkTo "about"}}/about{{/linkTo}}
{{#linkTo "guide"}}/guide{{/linkTo}}
{{#linkTo "animals"}}/animals{{/linkTo}}
{{#linkTo "animals.cats"}}/animals/cats{{/linkTo}}
{{#linkTo "animals.dogs"}}/animals/dogs{{/linkTo}}
</p>
<div class='outlet'>
{{ outlet }}
</div>
</div>
</script>
<script>
App = Ember.Application.create();
App.Router.map(function() {
this.resource("about");
this.resource("guide");
this.resource("animals", function() {
this.route("cats");
this.route("dogs");
})
});
App.IndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('about');
}
});
App.AnimalsIndexRoute = Ember.Route.extend({
redirect: function() {
this.transitionTo('animals.cats');
}
});
App.AnimalsCatsRoute = Ember.Route.extend({
setupController: function(controller, model) {
// BUG: this controller object has no connectOutlet method
// (uncomment to see this yourself)
// controller.connectOutlet('animal_mixin');
}
});
App.initialize();
</script>
</html>
本质上,animal_mixin 是一大块样板文件,我想重复使用它作为 mixin,通过在此处放置一个插座并将其连接到此模板,将其放置在任何我想要的地方。我意识到这个例子是人为的,因为我可以使用嵌套结构提供的“继承”来做到这一点:animal_mixin 的内容可以直接进入“动物”模板,我不需要在动物/猫和动物/狗。如果我想在所有动物中使用它会很好,但是假设我有另一个 /animals 的子路径,我不想包含这个片段。同样,这个例子是人为的,但我希望问题和意图是明确的。