如何创建依赖于普通变量、函数或逻辑的ember属性

How to create an ember property dependent on a normal variable, function or logic?

本文关键字:函数 属性 ember 变量 何创建 创建 依赖于      更新时间:2023-09-26

问题

我正在为emberjs制作传单视图,我遇到了一些问题。传单是一个外部库,有点与问题无关,但只需知道它是一个映射库。

考虑一个简单的属性,如缩放级别。传单地图实例具有可通过map.getZoom()访问和可通过map.setZoom(zoomLevel)分配的缩放级别。此外,用户可以与地图交互,并更改其缩放级别。传单允许我们在缩放变化时注册一个回调。

我希望我的"余烬传单"视图有一个zoomLevel余烬属性。这样我就可以从ember对象模型中获益(例如,将zoomLevel绑定到模板或另一个值),并且我们正在"以ember的方式"做这件事。

基础解决方案

我现在拥有的是Ember的一个子类。视图,带有缩放级别属性。在didInsertElement上,我创建了传单地图实例。代码有注释,应该是自解释的。

App.Leaflet = Ember.View.extend({
    classNames : ['ember-leaflet'],
    //default zoom level
    zoomLevel : 13,
    didInsertElement : function() {
        var self = this;
        var zoomLevel = this.get('zoomLevel');
        // create map instance
        var map = L.map(this.$().get(0)).setView(center, zoomLevel);
        // configure map instance...
        // Event listeners
        map.on('zoomend', function(e) {
            self.set('zoomLevel', e.target.getZoom());
        });
        // save map instance
        this.set('map', map);
    }
});

为了使这个问题更"可回答",我认为这个问题的解决方案应该满足以下要求:

  1. 当属性zoomLevel被改变时,地图应该相应地改变其缩放级别(使用map.setZoom(zoomLevel))
  2. 当用户交互地改变地图上的缩放时,zoomLevel属性应该被改变(可能使用传单地图的zoomend事件回调)

注意,我们在这里有一种"循环依赖",即"当zoomLevel更改时执行某事(setZoom on map)""当发生某事时(用户更改缩放),更改zoomLevel"。我想要一个解决方案,可以避免这种循环的观察者依赖。Ember的notifyPropertyChange可能是一个解决方案。

对于Ember的计算属性来说,这似乎是一个理想的任务,但我不知道在依赖属性字符串中放入什么。zoomLevel基本上是一个依赖于非ember属性的属性。


更新

我的第一次尝试是使用一个观察者来设置传单的缩放,并在传单zoomend上绑定一个事件来设置我的视图上的zoomLevel

问题:当我在zoomend传单事件上设置zoomLevel时,我将自动再次触发我的观察者。我说得清楚了吗?

那么,这一系列的事件发生了:

  1. 改变zoomLevel在交互式地图
  2. 传单触发zoomend事件
  3. zoomend事件回调集zoomLevel
  4. 观察者运行
  5. 在传单上不必要地调用setZoom

这是不有效的,但我不介意如果它工作。问题是,当用户非常快速地改变缩放多次(地图上一个简单的长滚动)时,观察者会被调用多次,这会混淆传单。

好的,我想我已经做到了。

我使用了一个计算属性和一个辅助属性。

App.Leaflet = Ember.View.extend({
    classNames : ['ember-leaflet'],
    //default zoom level
    zoomLevelValue : 13,
    zoomLevel : function(key, value){
        // getter
        if (arguments.length === 1) {
            var zoomLevel = this.get('zoomLevelValue');
            return zoomLevel;
        // setter  
        } else{
            var map = this.get('map');
            this.set('zoomLevelValue', value);
            map.setZoom(value);
            return value;
        }
    }.property('zoomLevelValue'),
    didInsertElement : function() {
        var self = this;
        var zoomLevel = this.get('zoomLevel');
        var map = L.map(this.$().get(0)).setView(center, zoomLevel);
        // configure map instance...
        // Event listeners
        map.on('zoomend', function(e) {
            console.log('zoomend', 'Setting zoomLevel '+e.target.getZoom());
            self.set('zoomLevelValue', e.target.getZoom());
        });
        // save map instance
        this.set('map', map);
    }
});

基本上有两种情况:

  1. zoomLevel被编程改变->我们更新地图上的缩放
  2. 缩放级别在地图上改变了->我们设置了辅助属性,计算机属性观察者也会得到通知,我们没有再设置地图上的缩放级别

然而我有一个新的问题,但我认为它与传单有关。当我调用setZoom时,另一个缩放动画在过程中,这个setZoom被忽略。例如,执行:

map.setZoom(1);
map.setZoom(12);

结束于1缩放级别。

也许传单上有关SO的问题会有帮助。

要从zoomLevel在ember到setZoom,你可以使用一个观察者。

如果要用另一种方式,你可能需要绑定一个事件到宣传单上的zoomChange

使用稍微不同的策略,我将zoomLevel作为属性并从函数中观察它,并且仅在属性的实际值与实际缩放值不同时才在地图上设置缩放。看这个小提琴http://jsfiddle.net/5As2z/30/我将逻辑传递给控制器,视图在插入文档

时设置映射。
App.ApplicationController = Ember.Controller.extend({
//default zoom level
zoomLevel: 13,
map: null,
zoomLevelChanged: function () {
    var zoomLevel = this.get('zoomLevel');
    var map = this.get('map');
    //Control not changing the zoom of the map if it is yet at the value
    if (zoomLevel != map.getZoom()) {
        map.setZoom(zoomLevel);
    }
}.observes('zoomLevel')});
App.ApplicationView = Ember.View.extend({
templateName: 'application',
didInsertElement: function () {
    var center = [41.3823000, 2.1825000];
    var controller = this.get('controller');
    var zoomLevel = controller.get('zoomLevel');
    var map = L.map('map').setView(center, zoomLevel);
    L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
        attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
    }).addTo(map);
    // configure map instance...
    // Event listeners
    map.on('zoomend', function (e) {
        console.log('zoomend', 'Setting zoomLevel ' + e.target.getZoom());
        controller.set('zoomLevel', e.target.getZoom());
    });
    // save map instance
    this.controller.set('map', map);
}});
html

<script type="text/x-handlebars" data-template-name="application">
    <h1> Leaflet map ember example </h1>
    {{view Ember.TextField valueBinding="zoomLevel"}}
    <div id="map"></div >
</script>