使用信息窗口添加多个标记(Google Maps API)

32

我目前正在使用以下代码通过Google Map API在地图上放置多个标记。

我的问题是出现了多个信息窗口不起作用的问题(只显示最后一个)。

这里有很多与我的问题类似的问题,实际上有大量的问题:

举个例子:尝试将多个InfoWindows绑定到Google Map上的多个标记并失败

我的解决方案有点简单:只需将点击监听器包含在(匿名的)函数中即可。

然而,我不明白为什么我的解决方案不起作用(将标记和信息窗口保存在数组中,而不是只有一个变量)。

    var markers = [];
    var infowindows = [];

    // add shops or malls
    for (var key in data.markers) {
      if (data.markers.hasOwnProperty(key)) {
        infowindows[key] = new google.maps.InfoWindow({
            content: data.markers[key].infowindow
        });

        markers[key] = new google.maps.Marker({
                position: new google.maps.LatLng(data.markers[key].location.lat, data.markers[key].location.lng),
                map: map,
                flat: true,
                title: data.markers[key].name,
                draggable: false
        });
        var iconFile = 'http://maps.google.com/mapfiles/ms/icons/'+marker_color+'-dot.png';
        markers[key].setIcon(iconFile);

        google.maps.event.addListener(markers[key], 'click', function() {
          infowindows[key].open(map, markers[key]);
        });
      }
    }

所以...我不想得到如何通过一些函数来封装监听器并让它工作的解决方案(尽管它应该可以工作,但我还没有测试过,会测试),但我想知道如果我将标记和信息窗口添加到数组中,为什么它不起作用。

6个回答

62

Javascript有一种语言结构叫做“闭包”。闭包是函数(如上面声明用于处理点击监听器的function() {})捕获了对外部变量的引用。

有很多资源比我更好地解释它们,建议您参考一下,但这是我的最佳尝试:

在这里的代码块中:

    google.maps.event.addListener(markers[key], 'click', function() {
      infowindows[key].open(map, markers[key]);
    });

因为“key”已经在外部定义为变量,所以该函数将捕获对该变量的引用。 所以您期望的是:

infowindows["helloworld"]

JavaScript会将此解释为:

infowindows[reference to key]
当您单击标记时,它会查找“关键字引用”以查看key的当前值。由于这可能直到循环完成后才会发生,因此key将等于data.markers对象中最后一个key的任何值。而且它将等于您添加的每个点击侦听器的值。 正如您指出的那样,解决方案是将其包装在匿名函数中,以使Javascript在添加单击侦听器时评估“key”的值。
  google.maps.event.addListener(markers[key], 'click', function(innerKey) {
      return function() {
          infowindows[innerKey].open(map, markers[innerKey]);
      }
    }(key));

54

对我来说这很好用!只需向标记对象添加一个新属性,该属性包含信息窗口对象。

var mytext = 'Infowindow contents in HTML'
var myinfowindow = new google.maps.InfoWindow({
    content: mytext
});

var marker = new google.maps.Marker({
    position: mypos,
    map: mymap,
    icon: myicon,
    title: mytitle,
    infowindow: myinfowindow
});

google.maps.event.addListener(marker, 'click', function() {
        this.infowindow.open(map, this);

});

5
这完全没有回答原来的问题!它只是展示了Google Maps API参考文档中一个信息窗口的例子。很抱歉,但这个回答不应该在这里。 - Zordid

20

有一种稍微简单的方法可以完成这个任务。你可以向标记添加自定义属性(信息窗口的索引),并在回调函数中引用它。以下是示例:

    markers = Array();
    infoWindows = Array();

    for(var i in earthquakes)
    {
        var location = new google.maps.LatLng(earthquakes[i].geolat, earthquakes[i].geolong);
        var marker = new google.maps.Marker({
            position : location,
            map : map,
            animation : google.maps.Animation.DROP,
            infoWindowIndex : i //<---Thats the extra attribute
        });
        var content = "<h3>" + earthquakes[i].title + "<h3>" +
                "<a data-ajax='false' target='_blank' href='" + earthquakes[i].link + "'>Link to shakemap.</a>";
        var infoWindow = new google.maps.InfoWindow({
            content : content
        });

        google.maps.event.addListener(marker, 'click', 
            function(event)
            {
                map.panTo(event.latLng);
                map.setZoom(5);
                infoWindows[this.infoWindowIndex].open(map, this);
            }
        );

        infoWindows.push(infoWindow);
        markers.push(marker);
    }

我正在尝试这种方法,但是我收到了jshint警告“不要在循环内创建函数”。如果我将监听器移到循环外面,则会得到“作用域外使用标记”的错误。我该如何避免这个问题? - aitor

2
    function addMarker(Latlng){ 
       marker = new google.maps.Marker({
            position: Latlng,
            icon:"myicon.jpg",
            map: map,
            animation: google.maps.Animation.DROP,
            title:"My tooltip"
        });

        //add marker
        marker.setMap(map);

        contentString = "<h1>Hello World</h1>";

        marker.infowindow = new google.maps.InfoWindow({
            content: contentString
        });

        //add click event
        google.maps.event.addListener(marker, 'click', function(){
            this.infowindow.open(map,this);
        });
    }

    addMarker(some_lat_lang_value);

1
我会使用闭包:
(function(infowindow, marker){google.maps.event.addListener(marker, 'click', function() {
  infowindow.open(map, marker);
});})(infowindow, marker)

0
var infowindow = null;
infowindow = new google.maps.InfoWindow({
  content: "loading..."
});
for (i = 0; i < data.dbreturn.length; i++) { 
  var latilongi = data.dbreturn[i].mapa.split(',');
  var mapinha =  {lat: parseFloat(latilongi['0']), lng:     parseFloat(latilongi['1'])};
  var marker = new google.maps.Marker({
  position: mapinha,
  html: '<div id="content"><h5 id="firstHeading"     class="firstHeading">'+data.dbreturn[i].nome+'</h5></div>'
});

google.maps.event.addListener(marker, "click", function () {
  infowindow.setContent(this.html);
  infowindow.open(map, this);
});
}

2
欢迎来到 Stack Overflow!虽然这段代码可能回答了问题,但提供关于为什么和/或如何回答问题的额外上下文可以提高其长期价值。 - Ajean

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接