Прокрутка маркеров с помощью API Карт Google v3 Проблема

Я не уверен, почему это не работает. У меня нет никаких ошибок, но что происходит, независимо от того, на каком маркере я нажимаю, он всегда нажимает на последний маркер. Я не уверен, почему, хотя потому, что the_marker настроен одинаково. Как я могу это исправить?:

(Обновлен с помощью нового jQuery + XML)

$(function(){
    var latlng = new google.maps.LatLng(45.522015,-122.683811);
    var settings = {
        zoom: 15,
        center: latlng,
        disableDefaultUI:true,
        mapTypeId: google.maps.MapTypeId.SATELLITE
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"), settings);

    $.get('mapdata.xml',{},function(xml){
        $('location',xml).each(function(i){
            the_marker = new google.maps.Marker({
                title:$(this).find('name').text(),
                map:map,
                clickable:true,
                position:new google.maps.LatLng(
                    parseFloat($(this).find('lat').text()),
                    parseFloat($(this).find('lng').text())
                )
            });
            infowindow = new google.maps.InfoWindow({
                content: $(this).find('description').text()
            });
            new google.maps.event.addListener(the_marker, 'click', function() {
                infowindow.open(map,the_marker);
            });
        });
    });
});

Ответ 1

У вас очень распространенная проблема закрытия в следующем цикле:

for(x in locations){
   console.log(x);
   infowindow[x] = new google.maps.InfoWindow({content: x});
   marker[x] = new google.maps.Marker({title:locations[x][0],map:map,position:locations[x][2]});
   google.maps.event.addListener(marker[x], 'click', function() {infowindow[x].open(map,marker[x]);});
}

Переменные, заключенные в закрытие, имеют одну и ту же единую среду, поэтому к моменту выполнения обратных вызовов click цикл запускает свой курс, а переменная x останется указателем на последнюю запись.

Вы можете решить это с еще большим количеством замыканий, используя функцию factory:

function makeInfoWindowEvent(map, infowindow, marker) {  
   return function() {  
      infowindow.open(map, marker);
   };  
} 

for(x in locations){
   infowindow[x] = new google.maps.InfoWindow({content: x});

   marker[x] = new google.maps.Marker({title: locations[x][0],
                                       map: map, 
                                       position: locations[x][3]});

   google.maps.event.addListener(marker[x], 'click', 
                                 makeInfoWindowEvent(map, infowindow[x], marker[x]);
}

Это может быть довольно сложная тема, если вы не знакомы с тем, как работают замыкания. Вы можете просмотреть следующую статью Mozilla для краткого введения:


UPDATE:

В дополнение к обновленному вопросу вы должны рассмотреть следующее:

  • Прежде всего, имейте в виду, что JavaScript не имеет области блока. Доступны только функции.

  • Когда вы назначаете переменную, которая ранее не была объявлена ​​с помощью ключевого слова var, она будет объявлена ​​как глобальная переменная. Это часто считается уродливой особенностью (или ошибкой) JavaScript, так как он может скрывать многие ошибки. Поэтому этого следует избегать. У вас есть два примера этих подразумеваемых глобальных переменных: the_marker и infowindow, и на самом деле именно поэтому ваша программа терпит неудачу.

  • У JavaScript есть закрытие. Это означает, что внутренние функции имеют доступ к переменным и параметрам внешней функции. Вот почему вы сможете получить доступ к the_marker, infowindow и map из функции обратного вызова метода addListener. Однако, поскольку ваши the_marker и infowindow рассматриваются как глобальные переменные, закрытие не работает.

Все, что вам нужно сделать, это использовать ключевое слово var при их объявлении, как показано в следующем примере:

$(function() {
   var latlng = new google.maps.LatLng(45.522015,-122.683811);

   var settings = {
      zoom: 15,
      center: latlng,
      disableDefaultUI: true,
      mapTypeId: google.maps.MapTypeId.SATELLITE
   };

   var map = new google.maps.Map(document.getElementById("map_canvas"), settings);

   $.get('mapdata.xml', {}, function(xml) {
      $('location', xml).each(function(i) {

         var the_marker = new google.maps.Marker({
            title: $(this).find('name').text(),
            map: map,
            clickable: true,
            position: new google.maps.LatLng(
               parseFloat($(this).find('lat').text()),
               parseFloat($(this).find('lng').text())
            )
         });

         var infowindow = new google.maps.InfoWindow({
            content: $(this).find('description').text();
         });

         new google.maps.event.addListener(the_marker, 'click', function() {
            infowindow.open(map, the_marker);
         });
      });
   });
});

Ответ 2

Вот мой подход.

for(x in locations){
    var name = locations[x][0];
    var latlng = locations[x][3];
    addMarker(map, name, latlng);
}

function addMarker(map, name, latlng){
    var infoWin = new google.maps.InfoWindow({content: name});
    var marker = new google.maps.Marker({
        map: map,
        position: latlng,
        title: name
    });
    google.maps.event.addListener(marker, 'click', function(){
        infoWin.open(map, marker);
    });
}