单击标记时,Google Maps v3会打开最后一个infoWindow

时间:2010-07-22 01:00:45

标签: javascript jquery google-maps closures

我的所有标记都有一个共享infoWindow。如果我使用jquery的$().each(function(){}),它会很好用,但是如果我将它更改为JavaScrips的native或while循环,它就不会按预期工作。

每当我点击一个标记时,它都会打开最后一个填充标记的infoWindow,而不是点击的标记infoWindow

这有效:

$(stores).each(function() {

   var storeId = $(this).attr('storeId');
   var address = $(this).attr('rawAddress');
   var city = $(this).attr('city');
   var state = $(this).attr('state');
   var zip = $(this).attr('zip');
   var lat = $(this).attr('lat');
   var lng = $(this).attr('lng');
   var distance = $(this).attr('distance');

   //create marker
   var point = new google.maps.LatLng(lat, lng);

   var marker = new google.maps.Marker({ position: point
     , map: InStorePickup.map
     , title: city + ' #' + storeId
   });

   //create infowindow content
   var infoWindowContent = '<div style="font-size: 8pt;">'
     + '<strong>' + city + ' #' + storeId + '</strong> (' + parseFloat(distance).toFixed(2) + 'mi)<br />'
     + address + '<br />' + city + ', ' + state + ' ' + zip
     + '</div>';

   google.maps.event.addListener(marker, 'click', function() {
     InStorePickup.openInfoWindow(marker, infoWindowContent);
   });

   bounds.extend(point);
 });

但这不起作用:

for (var i = 0; i < 3; i++) {
    var store = stores[i];

    var storeId = $(store).attr('storeId');
    var address = $(store).attr('rawAddress');
    var city = $(store).attr('city');
    var state = $(store).attr('state');
    var zip = $(store).attr('zip');
    var lat = $(store).attr('lat');
    var lng = $(store).attr('lng');
    var distance = $(this).attr('distance');

    //create marker
    var point = new google.maps.LatLng(lat, lng);

    var marker = new google.maps.Marker({ position: point
                  , map: InStorePickup.map
                  , title: city + ' #' + storeId
    });

    //create infowindow content
    var infoWindowContent = '<div style="font-size: 8pt;">'
                   + '<strong>' + city + ' #' + storeId + '</strong> (' + parseFloat(distance).toFixed(2) + 'mi)<br />'
                   + address + '<br />' + city + ', ' + state + ' ' + zip
                   + '</div>';

    google.maps.event.addListener(marker, 'click', function() {
        InStorePickup.openInfoWindow(marker, infoWindowContent);
    });

    bounds.extend(point);
}

有什么想法吗?

1 个答案:

答案 0 :(得分:4)

您将在for循环中拥有a very common closure problem。顺便提一句I have answered a similar question就这个话题就在昨天,您可能想要查看。

封闭在闭包中的变量共享相同的单一环境,因此在调用click回调时,循环将运行,infoWindowContent变量将指向最后一个分配给它的价值。

解决这个问题的一种方法是使用函数工厂进行更多闭包:

function makeInfoWindowListener (pMarker, pContent) {  
  return function() {
    InStorePickup.openInfoWindow(pMarker, pContent);
  };  
}


// ...

for (var i = 0; i < 3; i++) {

  // ...

  var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

  google.maps.event.addListener(
    marker, 
    'click', 
    makeInfoWindowListener(marker, infoWindowContent)
  );
}

如果你不熟悉闭包的工作方式,这可能是一个非常棘手的话题。您可能有兴趣查看以下文章以获得简要介绍:


<强>更新

jQuery示例的工作原因是因为传递给each()方法的函数将每个迭代都包含在自己的范围内。您可以在普通的JavaScript示例中实际执行相同的操作:

for (var i = 0; i < 3; i++) {

  // each iteration will now have its own scope
  (function () {

     var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

     google.maps.event.addListener(marker, 'click', function() {
       InStorePickup.openInfoWindow(marker, infoWindowContent);
     });

  })();
}

第二次更新:

请注意,第一个示例也可以使用匿名函数重写如下:

for (var i = 0; i < 3; i++) {

  // ...

  var infoWindowContent = '<div style="font-size: 8pt;">' + city + '...</div>';

  google.maps.event.addListener(marker, 'click', (function (pMarker, pContent) {  
    return function() {
      InStorePickup.openInfoWindow(pMarker, pContent);
    };  
  })(marker, infoWindowContent));
}