Ember旅程系列(十) -- 服务与工具

来源:互联网 发布:java文件转md5 编辑:程序博客网 时间:2024/05/17 08:56

英文原版:https://guides.emberjs.com/v2.13.0/tutorial/service/

对于Super Rentals应用,我们希望它能显示出每个出租点的位置。为了实现这个功能,我们进一步发掘Ember的潜力:

  1. 利用工具调用Google地图接口创建一个地图。
  2. 利用一个服务来将每个租赁地点的地图信息进行缓存。
  3. 利用一个组件来对租赁列表中的每个租赁点进行展示。

接入Google地图

在实现地图功能之前,我们需要在app中接入一个第三方的地图API。其实有很多方法可以在Ember中引入第三方库。你可以阅读依赖管理这一节来学习如何接入第三方库。

为了使用Google地图API,我们通过<script>来引入它。在app/index.html中加入对Google Maps API的引用:

app/index.html<!DOCTYPE html><html>  <head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <title>SuperRentals</title>    <meta name="description" content="">    <meta name="viewport" content="width=device-width, initial-scale=1">    {{content-for "head"}}    <link rel="stylesheet" href="{{rootURL}}assets/vendor.css">    <link rel="stylesheet" href="{{rootURL}}assets/super-rentals.css">    {{content-for "head-footer"}}  </head>  <body>    {{content-for "body"}}    <script src="{{rootURL}}assets/vendor.js"></script>    <script src="{{rootURL}}assets/super-rentals.js"></script>    <!-- 引入Google Maps API-->    <script src="https://maps.googleapis.com/maps/api/js?v=3.22"></script>    {{content-for "body-footer"}}  </body></html>

通过工具与Google Maps API交互

Ember工具几乎可以在Ember应用的各种各样的场景下使用并重用。就拿现在的Super Rentals来说,我们将通过Ember工具来与Google Maps API交互。此工具可以将Google Maps API从我们的Maps Service单独抽取出来。

既然已经引入了Google Maps API,接下来我们就来创建地图工具:

ember g util google-maps

上面这条命令会生成一个工具和一个单元测试文件。因为不需要对Google的代码进行测试,所以在这里我们就把测试文件删除了。

我们应用现在需要一个方法,用来调用google.maps.Map以生成地图,那就给这个方法取名createMap 好了。google.maps.Geocoder接口用来查询的目标的经纬度,google.maps.Marker用来做地图定位。

app/utils/google-maps.jsimport Ember from 'ember';const google = window.google;export default Ember.Object.extend({  init() {    this.set('geocoder', new google.maps.Geocoder());  },  createMap(element, location) {    let map = new google.maps.Map(element, { scrollwheel: false, zoom: 10 });    this.pinLocation(location, map);    return map;  },  pinLocation(location, map) {    this.get('geocoder').geocode({address: location}, (result, status) => {      if (status === google.maps.GeocoderStatus.OK) {        let geometry = result[0].geometry.location;        let position = { lat: geometry.lat(), lng: geometry.lng() };        map.setCenter(position);        new google.maps.Marker({ position, map, title: location });      }    });  }});

使用服务拉取地图数据

好了,我们现在创建了地图。接下来,继续。我们将创建一个地图服务,用来保持对上一步创建的地图对象的引用。同时将地图接入到页面的HTML元素上。

通过服务来操作地图API 有不少好处:

  1. 服务可以在被单独注入,这意味着它能将地图API单独抽取出来。方便日后的代码重构和维护。
  2. 服务是以懒加载形式引入,它直到被第一次调用的时候才会初始化。在某些场景,这在一定程度上可以减少app对cpu的负载及内存消耗。
  3. 服务是单例的,这意味着它在整个应用中只有一个实例。所以它能恒久远的保存地图数据,以至于当用户在应用内瞎逛然后又回到地图页面时,不用重新远程读取数据。

创建服务:

ember g service maps

紧接着编写此服务的代码。需要注意的是,我们首先需要判断一下有没有给定条件的地图存在,如果没有则需要调用Google Maps工具来创建它:

app/services/maps.jsimport Ember from 'ember';import MapUtil from '../utils/google-maps';export default Ember.Service.extend({  init() {    if (!this.get('cachedMaps')) {      this.set('cachedMaps', Ember.Object.create());    }    if (!this.get('mapUtil')) {      this.set('mapUtil', MapUtil.create());    }  },  getMapElement(location) {    let camelizedLocation = location.camelize();    let element = this.get(`cachedMaps.${camelizedLocation}`);    if (!element) {      element = this.createMapElement();      this.get('mapUtil').createMap(element, location);      this.set(`cachedMaps.${camelizedLocation}`, element);    }    return element;  },  createMapElement() {    let element = document.createElement('div');    element.className = 'map';    return element;  }});

通过组件来展示地图

基于服务和工具来讲地图渲染到页面是不够的,这里我们还需要一个组件来把这些环节串起来。

创建组件:

ember g component location-map

我们在app/templates/components/location-map.hbs中添加一个div元素,用它来做承载地图的容器:

app/templates/components/location-map.hbs<div class="map-container"></div>

下一步,完善我们的组件,让组件把地图输出到上面创建的div元素中。

我们通过在组件中创建一个属性来引入地图服务,属性就叫maps好了。服务可以在包括组件在内的Ember的任何对象内被注入。当你使用Ember.inject.service()来对Ember对象中的属性进行初始化的时候,Ember会自动的将与属性同名的服务注入

通过maps服务,我们可以调用一个名叫getMapElement的方法,并将location信息传入。我们通过didInsertElement()钩子方法将从服务中得到的地图放到容器元素内。此钩子函数会在组件渲染期间被调用:

app/components/location-map.jsexport default Ember.Component.extend({  maps: Ember.inject.service(),  didInsertElement() {    this._super(...arguments);    let location = this.get('location');    let mapElement = this.get('maps').getMapElement(location);    this.$('.map-container').append(mapElement);  }});

你或许发现了this.get(‘location’)这句代码中指定的location属性并没有被显示的定义。其实这个属性在引入组件的父模板文件中定义。

最后一步,打开rental-listing组件模板,并且引入刚刚新鲜出炉的location-map组件:

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>  <h3>{{rental.title}}</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属性定义在父模板中 -->  {{location-map location=rental.city}}</article>

开启服务器,看看我们成果:
这里写图片描述

本节完

原创粉丝点击