问题
I wrote this code:
<script type="text/javascript">
var address = JSON.parse('<?php echo $jsonLocations ?>');
console.log(address.locations[0]);
var latitude = '1';
var longitude = '1';
function initMap() {
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 12,
center: new google.maps.LatLng(latitude, longitude)
});
for(var i = 0; i < address.locations.length; i++){
new google.maps.Marker({
position: new google.maps.LatLng(address.locations[i]['lat'], address.locations[i]['long']),
map: map
}).addListener('click', function(){
new google.maps.InfoWindow({
content: '<div id="content">'+
'<div id="siteNotice">'+
'</div>'+
'<h5>' + i +'</h5>'+
'<div id="bodyContent">'+
'</div>'+
'</div>'
}).open(map, this);
})
}
}
</script>
I'm trying to display i onClick of the marker. So for the first maker I should be 0 and for the second 1. But somehow i is always the same value
回答1:
This is a classic closure problem.
The function which is using the i variable is a async callback.
The first thing what is happening is, that all the markers will be created. Therefore i will be address.locations.length at the end of the loop.
The async callbacks now reference this exact variable.
There are some possible fixes for this:
use the let statement if you are able to use ES6 JavaScript features:
for(let i = 0; i < address.locations.length; i++){
[...]
}
The second one is to create a closure with this exact binding:
for(var i = 0; i < address.locations.length; i++){
(function(i){
[...]
})(i)
}
The last option for you is to use the Function.bind method.
for(var i = 0; i < address.locations.length; i++){
new google.maps.Marker({
position: new google.maps.LatLng(address.locations[i]['lat'], address.locations[i]['long']),
map: map
}).addListener('click', (function(i){
new google.maps.InfoWindow({
content: '<div id="content">'+
'<div id="siteNotice">'+
'</div>'+
'<h5>' + i +'</h5>'+
'<div id="bodyContent">'+
'</div>'+
'</div>'
}).open(map, this);
}).bind(this,i))
}
I hope that one of this methods will work for you.
回答2:
This happens because the click event happens later in time and then i has the last value ...
To fix this you can use a self invoking anonymous function inside the for loop - this way you will create a scope for each loop and the value of i will remain for the click when it happens.
This is called Closure - you can read more about closures here and here
function initMap() {
var address = {
locations: [{
"lat": 30.53625,
"lng": -111.92674,
}, {
"lat": 33.53625,
"lng": -112.92674,
}, {
"lat": 32.53625,
"lng": -111.92674,
}, {
"lat": 33.53625,
"lng": -115.92674,
}]
};
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: new google.maps.LatLng(32.53625, -111.92674)
});
var markers = [];
for (var i = 0; i < address.locations.length; i++) {
(function(index) { /* <--- Self invoking function */
var marker = new google.maps.Marker({
position: new google.maps.LatLng(address.locations[index]['lat'], address.locations[index]['lng']),
map: map
});
marker.addListener('click', function() {
new google.maps.InfoWindow({
content: '<div id="content">' +
'<div id="siteNotice">' +
'</div>' +
'<h5>' + index + '</h5>' +
'<div id="bodyContent">' +
'</div>' +
'</div>'
}).open(map, this);
markers.push(marker);
});
})(i); /* <---- Pass the index to the closure to keep its value */
}
}
.as-console-wrapper{
display:none !important;
}
<script async defer type="text/javascript" src="https://maps.google.com/maps/api/js?sensor=false&callback=initMap"></script>
<div id="map" style="width:500px;height:150px"></div>
来源:https://stackoverflow.com/questions/45483689/add-onclick-listener-to-google-maps-markers-javascript