英文原版:https://guides.emberjs.com/v2.13.0/tutorial/subroutes/
截止到目前,我们已经生成了4个顶层路由:
- about路由,用来展示app的信息。
- contact路由,显示公司的联系方式。
- rentals路由,向用户展示租赁信息。
- index路由,被设置为将用户重定向到rentals路由。
rentals路由承载了许多的功能。通过直接的旅程,我们知道当中包含的搜索功能,以及展示详情的功能。为了更好了满足这些需求,接下来我们将会通过Ember的嵌套路由特性来实现相应的功能。
在本章的末尾,我希望我们能创建下面这个新的路由:
- rentals/index路由,用来显示租赁的摘要,上面罗列出所有有效的信息。此路由将会在用户访问rentals URL时被默认显示。
- rentals/show路由,用来显示租赁的摘要,并且会显示被选中的信息的详情。show路由会被当前显示的租赁信息数据中的id值所取代。(rentals/grand-old-mansion,grand-old-mansion–当前显示的租赁信息的数据id)
父路由
在之前的路由与模板张杰,我们创建了rentals路由。
打开rentals路由的模板,可以看到{{outlet}}在模板内容的最下面。它的意义就是:展示当前嵌套路由的内容。
app/templates/rentals.hbs
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to 'about' class="button"}}
About Us
{{/link-to}}
</div>
{{#list-filter
filter=(action 'filterByCity')
as |rentals|}}
<ul class="results">
{{#each rentals as |rentalUnit|}}
<li>{{rental-listing rental=rentalUnit}}</li>
{{/each}}
</ul>
{{/list-filter}}
{{outlet}}
拥有父路由就意味着,任何在父路由上的内容将会将会作为公用内容出现在页面上,是固定不变的;子路由内容会随着路由地址的变化而变化。
创建嵌套的index路由
第一个即将创建的嵌套路由将会是index路由。嵌套的index路由的运行方法与根index路由一样。当没有指定路由时,index路由将会是默认的路由。既在我们的项目中,如果你访问/rentals路由,则Ember首先会试图加载/rentals/index路由。
命令:
ember g route rentals/index
如果你打开app/router.js,你会注意到rentals哪行代码不一样了。出现了一个function(){},它就是为了嵌套路由而存在。这个路由会映射到/rentals/index :
app/router.js
Router.map(function() {
this.route('about');
this.route('contact');
<!-- 映射到/rentals/index -->
this.route('rentals', function() {});
});
这下知道index路由是做什么的了吧??index路由默认隐式存在。Ember会知道你要访问index路由。但是,如果你想自定义index路由,你仍然可以显示的加上它。比如,你将index路由按你的意愿指定:
this.route('index', { path: '/custom-path'})
在使用Ember Data这一章节,我们通过对store service的调用来获取全部数据。现在让我们将这个代码转移到/rentals/index子路由中去:
app/routes/rentals.js
export default Ember.Route.extend({
/*
model() {
return this.get('store').findAll('rental');
}
*/
});
app/routes/rentals/index.js
export default Ember.Route.extend({
model() {
return this.get('store').findAll('rental');
}
});
好了,现在我们将在子路由中返回所有数据。同样地,将rentals模板中展示数据的代码也转移到子路由的模板中去:
app/templates/rentals.hbs
<div class="jumbo">
<div class="right tomster"></div>
<h2>Welcome!</h2>
<p>We hope you find exactly what you're looking for in a place to stay.</p>
{{#link-to 'about' class="button"}}
About Us
{{/link-to}}
</div>
<!-- 以下代码转移到子路由模板中 -->
{{#list-filter
filter=(action 'filterByCity')
as |rentals|}}
<ul class="results">
{{#each rentals as |rentalUnit|}}
<li>{{rental-listing rental=rentalUnit}}</li>
{{/each}}
</ul>
{{/list-filter}}
<!-- end -->
{{outlet}}
app/templates/rentals/index.hbs
{{#list-filter
filter=(action 'filterByCity')
as |rentals|}}
<ul class="results">
{{#each rentals as |rentalUnit|}}
<li>{{rental-listing rental=rentalUnit}}</li>
{{/each}}
</ul>
{{/list-filter}}
{{outlet}}
最后,我们需要让控制器来为新的嵌套路由服务。因为过滤功能必不可少。
创建新的控制器:
ember g controller rentals/index
除了将rentals控制器中的代码复制过来之外,我们还有个更聪明的方法。在rentals/index 控制器中导入rentals控制器:
app/controllers/rentals/index.js
import RentalsController from '../rentals';
export default RentalsController;
为子路由配置数据
下一步,我们将会再创建一个子路由用来显示指定的租赁信息。因此需要更新几个文件。为了找到指定的信息,我们将会需要 Ember Data的 findRecord()(点击此处查看详细介绍)。findRecord()需要我们提供一个唯一的key值。
并且对于show路由,我们仍然希望它能展示一些被我们指定查询信息的额外信息。
为了实现它,我们要更新一些Mirage的config.js文件,我们在安装插件这一章节中提到过它。让我们来升级它:
mirage/config.js
export default function() {
this.namespace = '/api';
let rentals = [
{
type: 'rentals',
id: 'grand-old-mansion',
attributes: {
title: "Grand Old Mansion",
owner: "Veruca Salt",
city: "San Francisco",
propertyType: "Estate",
bedrooms: 15,
image: "https://upload.wikimedia.org/wikipedia/commons/c/cb/Crane_estate_(5).jpg",
description: "This grand old mansion sits on over 100 acres of rolling hills and dense redwood forests."
}
},
{
type: 'rentals',
id: 'urban-living',
attributes: {
title: "Urban Living",
owner: "Mike Teavee",
city: "Seattle",
propertyType: "Condo",
bedrooms: 1,
image: "https://upload.wikimedia.org/wikipedia/commons/0/0e/Alfonso_13_Highrise_Tegucigalpa.jpg",
description: "A commuters dream. This rental is within walking distance of 2 bus stops and the Metro."
}
},
{
type: 'rentals',
id: 'downtown-charm',
attributes: {
title: "Downtown Charm",
owner: "Violet Beauregarde",
city: "Portland",
propertyType: "Apartment",
bedrooms: 3,
image: "https://upload.wikimedia.org/wikipedia/commons/f/f7/Wheeldon_Apartment_Building_-_Portland_Oregon.jpg",
description: "Convenience is at your doorstep with this charming downtown rental. Great restaurants and active night life are within a few feet."
}
}
];
this.get('/rentals', function(db, request) {
if (request.queryParams.city !== undefined) {
let filteredRentals = rentals.filter(function (i) {
return i.attributes.city.toLowerCase().indexOf(request.queryParams.city.toLowerCase()) !== -1;
});
return { data: filteredRentals };
} else {
return { data: rentals };
}
});
/***** 赋予它更强大的功能 *****/
this.get('/rentals/:id', function (db, request) {
return { data: rentals.find((rental) => request.params.id === rental.id) };
});
}
创建子路由
好了,我们的API已经就绪了。现在可以创建show路由的子路由了。
命令:
ember g route rentals/show
输出:
installing route
create app/routes/rentals/show.js
create app/templates/rentals/show.hbs
updating router
add route rentals/show
installing route-test
create tests/unit/routes/rentals/show-test.js
让我们瞧一眼变化:
app/router.js
Router.map(function() {
this.route('about');
this.route('contact');
this.route('rentals', function() {
this.route('show');
});
});
新路由嵌套在rentals路由内。这会告诉Ember,访问该子路由对应的URL是:
localhost:4200/rentals/show
为了告诉应用我们想要了解哪条租赁信息,我们需要用租赁信息ID来代替”show”。当然,我们需要让URL清楚明了:
localhost:4200/rentals/id-for-rental
为了满足需求,更新router.js:
app/router.js
Router.map(function() {
this.route('about');
this.route('contact');
this.route('rentals', function() {
/** 添加映射 **/
this.route('show', { path: '/:rental_id' });
});
});
rental_id的值将会传递给/rentals/show路由。
通过ID查找
下一步,让show路由可以通过传递过来的参数来查询对应租赁信息:
app/routes/rentals/show.js
export default Ember.Route.extend({
model(params) {
return this.get('store').findRecord('rental', params.rental_id);
}
});
只要我们在show路由上添加了” :rental_id “,rental_id就会被封装在params中传递给model()钩子。当我们这样调用
this.get('store').findRecord('rental', params.rental_id)
时,Ember Data就是发送一条HTTP GET请求。
添加租赁信息到模板
下一步,更新模板,让它展示出租赁信息:
app/templates/rentals/show.hbs
<div class="jumbo show-listing">
<h2 class="title">{{model.title}}</h2>
<div class="right detail-section">
<div class="detail owner">
<strong>Owner:</strong> {{model.owner}}
</div>
<div class="detail">
<strong>Type:</strong> {{rental-property-type model.propertyType}} - {{model.propertyType}}
</div>
<div class="detail">
<strong>Location:</strong> {{model.city}}
</div>
<div class="detail">
<strong>Number of bedrooms:</strong> {{model.bedrooms}}
</div>
<p class="description">{{model.description}}</p>
</div>
<img src="{{model.image}}" class="rental-pic">
</div>
ok,打开浏览器/服务器。访问localhost:4200/rentals/grand-old-mansion,你将会看到惊喜。
链接到指定的租赁信息
现在我们做到了单独展示某一条租赁详情。我们会在rental-listing组件中添加一个超链接(通过link-to助手),用来链接到指定的某个租赁详情页。link-to助手接受路由名称和数据模型对象为参数。若你将一个对象作为第二个参数传递给link-to助手,默认的,助手会将数据的ID序列化到URL中。所以,你只需要将id值当做参数即可。
点击标题,就会读取租赁详情:
app/templates/components/rental-listing.hbs
<article class="listing">
<a {{action 'toggleImageSize'}} class="image {{if isWide "wide"}}">
<img src="{{rental.image}}" alt="">
<small>View Larger</small>
</a>
<!-- 添加link-to助手 -->
<h3>{{#link-to "rentals.show" rental}}{{rental.title}}{{/link-to}}</h3>
<div class="detail owner">
<span>Owner:</span> {{rental.owner}}
</div>
<div class="detail type">
<span>Type:</span> {{rental-property-type rental.propertyType}}
- {{rental.propertyType}}
</div>
<div class="detail location">
<span>Location:</span> {{rental.city}}
</div>
<div class="detail bedrooms">
<span>Number of bedrooms:</span> {{rental.bedrooms}}
</div>
{{location-map location=rental.city}}
</article>
大功还有一点就告成!截止到此,你就可以将你的超级租赁app部署上线,面向全球了!!!!你可以利用这个项目作为初次探索Ember的启蒙项目。上帝保佑,我们真心希望本次旅程会让你受益匪浅,也希望借这次旅程打开你探索Ember的大门。
本节完