2010-07-22 70 views
2

對於我所有的標記,我都有一個共享infoWindow。如果我使用jquery的$().each(function(){}),但如果將其更改爲JavaScrips的native或while循環,它的工作效果不錯,但它不能按預期工作。當點擊標記時,Google Maps v3會打開最後一個信息窗口

每當我點擊一個標記,它將打開最後一個填充標記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); 
} 

有什麼想法?

回答

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) 
); 
} 

這可以說是相當棘手的話題,如果你不熟悉閉包是如何工作的。你可能有興趣在檢查出下面的文章作一簡要介紹:


UPDATE:

爲什麼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); 
    }); 

    })(); 
} 

月2日更新:

注意第一個例子也可以使用匿名函數改寫爲:

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)); 
} 
+0

感謝丹尼爾的幫助,鏈接非常豐富。 你的第二個解決方案適用於我,但第一個解決方案沒有。 關於你的第一個解決方案,你的意思是? google.maps.event.addListener(marker,'click',makeInfoWindowListener(marker,infoWindowContent)); 爲我工作。 哪一個你喜歡你的2個解決方案? – 2010-07-22 16:56:53

+0

@ koderoid:哎呀,你說得對第一個例子。我在那裏有一個大的複製/粘貼錯誤。正如你發現的那樣,整個'InStorePickup.openInfoWindow'是不必要的。修正了我的答案...請注意,工廠方法可以使用匿名函數「內聯」,如我最新答案的最後一個示例所示。關於我的偏好,我更習慣於最後一種方法,但這只是個人品味的問題。 – 2010-07-22 17:58:24

+0

是的,我同意。第二種方法看起來更容易,這也是我的口味,但它可能會有一些性能折衷。順便說一句,你對第一個解決方案的更新也很好,我將實際使用它。 謝謝, – 2010-07-22 18:50:33

相關問題