【问题标题】:GoogleMaps API with Emberjs带有 Ember Js 的 Google Maps API
【发布时间】:2015-11-12 13:58:59
【问题描述】:

我有一个带有 EmberJs 视图的 GoogleMap。除了数据绑定,一切都很好。

我想将地图标记与 ember-data 绑定。如果数据级别发生变化,它必须反映在 Map 上。

我尝试使用观察者,并重新运行 makeMarkers 方法来设置标记,但这似乎是一个不好的解决方案。

将数据与 GoogleMaps 绑定的最佳方式是什么?

【问题讨论】:

    标签: javascript google-maps ember.js coffeescript emblem.js


    【解决方案1】:

    视图在 Ember 2.0 上已弃用,它们将在 Ember 2.5 中被删除,制作一个类似的组件:{{g-map markers=models}}

    这个组件有一个项目集合,这里是markers
    你可以实现这样的东西:

    import Ember from 'ember';
    import MarkerSync from '../mixin/marker-synchronizer';
    
    /**
     * Basic Component to display a google map,
     * Service & Marker have to be improved
     **/
    export default Ember.Component.extend(MarkerSync, {
        classNames: 'google-map',
        googleMap: Ember.inject.service(),
        map: null,
    
        mapOptions: function () {
            return {
                center: new google.maps.LatLng(-34.397, 150.644),
                zoom: 8
            };
        },
    
        didInsertElement: function () {
            this.$().height('100%');
            this.$().width('100%');
            this.displayGmap();
            jQuery(window).on('resize', Ember.run.bind(this, this.handleResize));
        },
    
        willInsertElement: function () {
            this.get('googleMap').loadScript();
        },
    
        displayGmap: Ember.observer('googleMap.isLoaded', function () {
            if (!this.get('googleMap.isLoaded')) {
                return;
            }
            const mapOptions = this.mapOptions();
            this.set('map', new google.maps.Map(this.$()[0], mapOptions));
        }),
    
        handleResize: function () {
            if (!this.get('googleMap.isLoaded')){
                return;
            }
            const map = this.get('map');
            const center = map.getCenter();
            google.maps.event.trigger(map, 'resize');
            map.setCenter(center);
        },
    });
    
    import Ember from 'ember';
    
    /**
     * Synchronize collection with map from component.
     * Care about to display or remove marker from map,
     * Be careful this is not optimized.
     **/
    export
    default Ember.Mixin.create({
        markers: null,
        _gHash: Ember.A(),
        init() {
            this._super.apply(this, arguments);
            /*
            * observes markers array.
            */
            this.get('markers').addArrayObserver({
                arrayWillChange: Ember.run.bind(this, this.markersWillChange),
                arrayDidChange: Ember.run.bind(this, this.markersDidChange)
            });
        },
    
        /*
        * Remove marker from array and remove from map
        */
        markerRemoved(marker) {
            let gMarker = this.get('_gHash').find(function(item) {
                return item.related === marker;
            });
            gMarker.native.setMap(null);
            this.get('_gHash').removeObject(gMarker);
        },
    
        /*
        * Add marker to `synchronized` array and display on map
        */
        markerAdded(marker) {
            const gMarker = new google.maps.Marker({
                position: {
                    lat: marker.lat,
                    lng: marker.lng
                },
                title: marker.title,
                map: this.get('map'),
            });
            this.get('_gHash').push({
                native: gMarker,
                related: marker
            });
        },
    
        /*
        * Take care about removed item
        */
        markersWillChange(markers, start, removeCount, addCount) {
            if (removeCount > 0) {
                for (let i = start; i < start + removeCount; i++) {
                    this.markerRemoved(markers.objectAt(i));
                }
            }
        },
    
        /*
        * Take care about added item
        */
        markersDidChange(markers, start, removeCount, addCount) {
            if (addCount > 0) {
                for (let i = start; i < start + addCount; i++) {
                    this.markerAdded(markers.objectAt(i));
                }
            }
        },
    });
    
    import Ember from 'ember';
    
    const get = Ember.get;
    
    /**
    * This service lazy load googleMap api.
    * Ugly but do the job
    */
    export default Ember.Service.extend({
    
        scriptUrl: 'https://maps.googleapis.com/maps/api/js',
        isLoaded: Ember.computed.equal('state', 'loaded'),
        state: 'none',
    
        init: function () {
            let config = this.container.lookupFactory('config:environment');
            var apiKey = get(config, 'googleMap.apiKey');
            this.set('apiKey', apiKey);
        },
    
        normalizeUrl: function () {
            var url = this.get('scriptUrl');
            url += '?' + 'v=3' + '&' + 'libraries=places' + '&' + 'callback=loadGmap';
            if (this.get('apiKey')) {
                url += '&key=' + this.get('apiKey');
            }
            return url;
        },
    
        loadScript: function () {
            if (this.get('state') !== 'none'){
                return false;
            }
            this.set('state', 'loading');
            window.loadGmap = Ember.run.bind(this, function () {
                this.set('state', 'loaded');
            });
            var url = this.normalizeUrl();
            return Ember.$.getScript(url).fail(function(){
                console.log('getScript fail');
            });
        },
    });
    

    此实现有效,但您必须“清理”此代码:)

    【讨论】:

      【解决方案2】:

      1) 创建组件,而不是视图

      2) 使用didInsertElement 渲染谷歌地图和观察者来更新它。不要忘记观察者是同步的(http://guides.emberjs.com/v1.13.0/object-model/observers/),你需要这样做:

      somethingChanged: Ember.observer('something', function () {
          Ember.run.once(this, '_somethingChanged');
      }).on('init'),
      _somethingChanged: function () {
          /* do smth about changed property here */
      }
      

      【讨论】:

      • 如果我使用组件,那么如何访问其中的模型数据?
      • 您可以将任何数据传递给您的组件:{{my-component data=model someParam=someValue}},您甚至可以通过这种方式传递store(不是最佳决策,但在极少数情况下您可能需要它)
      • 谢谢,到目前为止,您的建议似乎对我有用。现在有两件事,1> 如何在 _somethingChanged 中获取唯一更改的对象? 2> 如果我没有得到更改的对象并尝试为所有数据重新运行 makeMarkers,它会开始多次制作标记..
      • 您的意思是您将数组传递给组件并且需要知道更改了哪个元素?我不明白
      • 是的,我传递了一个数组,如果该数组内部的某些属性值发生变化,我想获取该对象。
      猜你喜欢
      • 2012-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 2012-12-07
      • 1970-01-01
      相关资源
      最近更新 更多