Ember旅程系列(十一) -- 嵌套路由

英文原版: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的大门。

本节完

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值