странное поведение маркерных событий в OpenLayer - PullRequest
2 голосов
/ 29 января 2011

Эй. У меня есть слой маркеров на моей карте.

Каждый раз, когда я добавляю новый маркер, я регистрирую его в событии щелчка мыши:

var lonlat = new OpenLayers.LonLat(lon,lat);
var marker = new OpenLayers.Marker(lonlat,icon);
marker.id = callId;

marker.events.register("mousedown", marker, function() {AddPopup(marker.id);});

callMarkers.addMarker(marker);

Иногда я хочу отключить / включить событие. поэтому я использую эти функции:

function EnableAllMarkers()
{ 
    for (var i in callMarkers.markers)
    {
        callMarkers.markers[i].events.remove("mousedown");               

        callMarkers.markers[i].events.register("mousedown", callMarkers.markers[i],   

        function() { AddPopup(callMarkers.markers[i].id); });
    }  
}


function DisableAllMarkers()
{ 
    for (var i in callMarkers.markers)
    {
        callMarkers.markers[i].events.remove("mousedown");
    }  
}

Когда я использую этот код, я получаю странное поведение - иногда открывается всплывающее окно для неправильного маркера. Я нажимаю на маркер X и открывается всплывающее окно Y.

кто-нибудь может мне помочь, пожалуйста?

примечание: Причина, по которой EnableAllmMarkers сначала удаляет событие, заключается в том, что мы не знаем, вызывался ли DisableAllmMarkers с момента добавления нового маркера. если он был вызван действительно, функция удаления ничего не сделает.

Ответы [ 2 ]

7 голосов
/ 29 января 2011

Это классическая ловушка JavaScript: вы создаете экземпляры функций как обработчики событий в цикле, а функции ссылаются на локальную переменную. Проблема в том, что все из них ссылаются на одну и ту же локальную переменную: одну и ту же, единственную, уникальную переменную только в одном месте в памяти. Переменная в этом случае - «i».

В конце этого цикла for «i» будет иметь значение последнего ключа в объекте (и, кстати, если callMarkers.markers действительно массив, то это не должно быть for ... in цикл в любом случае, но это отдельная проблема). Когда эти события наконец срабатывают, следовательно, все обработчики будут делать свое дело с "i", равным этому одному и тому же ключу.

Исправить:

  for (var i in callMarkers.markers)
    {
        callMarkers.markers[i].events.remove("mousedown");               

        callMarkers.markers[i].events.register(
          "mousedown", 
          callMarkers.markers[i],
          (function(ii) {
            return function() {
              AddPopup(callMarkers.markers[ii].id);
            }
          )(i)
         );
    } 

Это вводит посредническую анонимную функцию. Эта функция вызывается немедленно и передается текущее значение «i». Делая это & ​​mdash; передача «i» в качестве аргумента анонимной функции & mdash; значение «захвачено» в аргументе «ii». Каждая итерация цикла вызовет другой вызов анонимной функции, и функция, которую она возвращает (фактический обработчик), получит доступ к своей собственной закрытой переменной «ii».

Есть и другие способы достижения того же самого, но это всего лишь вариации на эту тему.

0 голосов
/ 10 декабря 2011

У меня была такая же проблема, когда событие зарегистрировано в конкретном Создателе, оно запускается и для всех остальных Маркер.Наконец-то я смог ее решить.Я должен был зарегистрировать отдельные события для каждого маркера.Вот мой код:

    var makerCount=0; // I want only 2 Markers to be shown : Source,Destination

function setMarkers(x,y){
    var icon = new OpenLayers.Icon('http://www.openlayers.org/dev/img/marker.png',size,offset);  

 if(makerCount<2){

    if(makerCount==0){  // Source
       var location = new OpenLayers.LonLat(x,y); 

       var size = new OpenLayers.Size(21,25);
       var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);

        var sourceMarker=new OpenLayers.Marker(location,icon)
        sourceMarker.events.register('mousedown', sourceMarker, function(evt) { 
                alert('Source :: X='+ x + ' , Y=' + y); 
                OpenLayers.Event.stop(evt); }); 


        markers.addMarker(sourceMarker); 
        markers.setOpacity(0.2);
        makerCount++;
    }else{ // Destination

        var location = new OpenLayers.LonLat(x,y); 

        var size = new OpenLayers.Size(21,25);
        var offset = new OpenLayers.Pixel(-(size.w/2), -size.h);
        var halfIcon = icon.clone();  

        var destinationMarker=new OpenLayers.Marker(location,halfIcon)
        destinationMarker.events.register('mousedown', destinationMarker, function(evt) { 
                alert('Destination :: X='+ x + ' , Y=' + y); 
                OpenLayers.Event.stop(evt); 
           });          
        markers.addMarker(destinationMarker); 
        halfIcon.setOpacity(0.5);
        makerCount++;
    }

 }
}
...