关闭Google Maps API v3中的所有信息窗口

75

我正在编写一个脚本,在我的网站上创建一个带有多个标记的谷歌地图画布。当你点击标记时,我想要弹出信息窗口。我已经实现了这个功能,目前的代码如下:

 var latlng = new google.maps.LatLng(-34.397, 150.644);
    var myOptions = {
      zoom: 8,
      center: latlng,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
    function addMarker(map, address, title) {
     geocoder = new google.maps.Geocoder();
     geocoder.geocode( { 'address': address}, function(results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
          map.setCenter(results[0].geometry.location);
          var marker = new google.maps.Marker({
     position: results[0].geometry.location,
              map: map,
              title:title
    });
    google.maps.event.addListener(marker, 'click', function() {
     var infowindow = new google.maps.InfoWindow();
            infowindow.setContent('<strong>'+title + '</strong><br />' + address);
             infowindow.open(map, marker);

          });
        } else {
          alert("Geocode was not successful for the following reason: " + status);
        }
     });
    }
    addMarker(map, 'Address', 'Title');
 addMarker(map, 'Address', 'Title');

这段代码已经100%可用。但是我想实现当一个信息窗口打开时,如果你想打开第二个,第一个会自动关闭。但我还没有找到解决方法。infowindow.close()不管用。有人有这个问题的例子或解决方案吗?

12个回答

165

infowindow 是局部变量,而在 close() 函数执行时 window 不可用。

var latlng = new google.maps.LatLng(-34.397, 150.644);
var infowindow = null;

...

google.maps.event.addListener(marker, 'click', function() {
    if (infowindow) {
        infowindow.close();
    }
    infowindow = new google.maps.InfoWindow();
    ...
});
...

9
谢谢您。我将我的代码从拥有多个信息窗口更改为只有一个信息窗口,并在每次标记器点击时打开/关闭。效果很好。 - William
@William,你能否在这里发布一段你所写的代码片段并分享给大家? - Carl
运行完美 :-) 我正在使用SnazzyInfoWindow.js来创建信息窗口,并尝试了这个解决方案。谢谢。 - Aamer Shahzad
1
Infowindow有一个setContent()方法。如果您不需要同时打开多个Infowindow,请仅使用一个实例并动态设置其内容。这段代码在性能方面很差。 - MrUpsidown

16

声明全局变量:

var mapOptions;
var map;
var infowindow;
var marker;
var contentString;
var image;

initialize函数中,使用地图的addEvent方法:

google.maps.event.addListener(map, 'click', function() {
    if (infowindow) {
        infowindow.close();
    }
});

7

为了动态创建infowindows的循环,需要声明一个全局变量:

var openwindow;

然后在addListener函数调用中(在循环内部):

google.maps.event.addListener(marker<?php echo $id; ?>, 'click', function() {
if(openwindow){
    eval(openwindow).close();
}
openwindow="myInfoWindow<?php echo $id; ?>";
myInfoWindow<?php echo $id; ?>.open(map, marker<?php echo $id; ?>);
});

请问您能解释一下在这里使用eval的目的吗? - Anis LOUNIS aka AnixPasBesoin
如果我们不使用 eval,那么“openwindow”就是一个字符串,语句将会被执行为“openwindow.close()”,而不是“myInfoWindow1.close()”。请查看此处的错误信息:https://jsfiddle.net/ts3z6nw6/1/ - Binod Kalathil
我的信息窗口是通过JS添加的 - 我使用了相同的方法,声明openwindow在我的forEach()之外,它创建具有窗口的标记。在我的代码中,我不需要使用eval,因为openwindow已经是openwindow对象。 - GuruBob
你在Firefox中测试过吗?我在Firefox中遇到了错误。 - Binod Kalathil
我用这种方法取得了成功,除了我将openWindow初始化为一个infowindow,所以不需要eval。 - user3080408
在 Firefox 上,需要使用 eval。如果不是字符串,则会抛出错误“TypeError:openwindow.close 不是函数”。 - Dennis

2
在 script 标签开始标记后面添加以下这行代码。
previous_Window=null;

使用这段代码可以让它百分之百地工作。

 radius= circle.getRadius()/1000;
 radius_mile= circle.getRadius()/1609.344;

 newRadious = 'This Circle Radius Covers Approx ' + radius.toFixed(1) + ' Km'+' <br> This circle Radius Covers Approx '+ radius_mile.toFixed(1)+ 'Miles';
            var infoWindow= new google.maps.InfoWindow({
              content: newRadious
              });
 infoWindow.setContent(newRadious)
 infoWindow.setPosition(circle.getCenter());
 if (previous_Window) 
  previous_Window.close();

  infoWindow.open(map);
  previous_Window=infoWindow;

1

我有一份代码示例,可能会有所帮助。我设置了一个全局范围内的infowindow对象,然后在显示之前使用setContent()来设置内容。

  let map;
  let infowindow;
  let dataArr = [
    {
      pos:{lat: -34.397, lng: 150.644},
      content: 'First marker'
    },
    {
      pos:{lat: -34.340, lng: 150.415},
      content: 'Second marker'
    }
  ];

  function initMap() {
    map = new google.maps.Map(document.getElementById('map'), {
      center: {lat: -34.397, lng: 150.644},
      zoom: 8
    });
    // Set infowindow object to global varible
    infowindow = new google.maps.InfoWindow();
    loadMarker();
  }

  function loadMarker(){
    dataArr.forEach((obj, i)=>{
      let marker = new google.maps.Marker({
        position: obj.pos,
        map: map
      });
      marker.addListener('click', function() {
        infowindow.close()
        infowindow.setContent(`<div> ${obj.content} </div>`)
        infowindow.open(map, marker);
      });
    })
  }

0

我有一个动态循环,根据输入到CMS中的数量创建infowindows和标记,因此我不想在每次事件单击时创建新的InfoWindow()并用请求拖慢它,如果这种情况曾经出现。相反,我试图知道每个实例的特定infowindow变量将是我拥有的一组位置中的哪一个,并提示Maps在打开正确的窗口之前关闭所有窗口。

我的位置数组称为locations,因此我在实际地图初始化之前设置了PHP来获取我的infowindow变量名称:

for($k = 0; $k < count($locations); $k++) {
        $infowindows[] = 'infowindow' . $k; 
} 

然后在初始化地图等操作之后,在脚本中我使用了 PHP 的 foreach 循环,通过计数器创建动态信息窗口:

//...javascript map initilization
<?php 
$i=0;
foreach($locations as $location) {

    ..//get latitudes, longitude, image, etc...

echo 'var mapMarker' . $i . ' = new google.maps.Marker({
          position: myLatLng' . $i . ',
          map: map,
          icon: image
      });';

echo 'var contentString' . $i . ' = "<h1>' . $title[$i] . '</h1><h2>' . $address[$i] . '</h2>' . $content[$i] .         '";'; 
echo 'infowindow' . $i . ' = new google.maps.InfoWindow({ ';
echo '    content: contentString' . $i . '
          });';

echo 'google.maps.event.addListener(mapMarker' . $i . ', "click", function() { ';   
    foreach($infowindows as $window) {  
        echo $window . '.close();'; 
    }
        echo 'infowindow' . $i . '.open(map,mapMarker'. $i . ');
      });';

$i++; 
}
?>
...//continue with Maps script... 

所以,问题是,在我调用整个地图脚本之前,我有一个数组,其中包含我知道在创建InfoWindow()时将输出的名称,例如infowindow0、infowindow1、infowindow2等

然后,在每个标记的click事件上,foreach循环遍历并关闭所有这些信息窗口,然后再执行下一步打开它们。最终代码看起来像这样:

google.maps.event.addListener(mapMarker0, "click", function() {
    infowindow0.close();
    infowindow1.close();
    infowindow2.close();
    infowindow0.open(map,mapMarker0);
}

我想这只是一种不同的做事方式...但我希望它能帮助到某些人。


5
这是一段很难维护的代码,我认为.. 为什么不用PHP打印一个JSON数组,并将其提供给一些JavaScript代码呢? - Sam Vloeberghs

0

我有类似以下的东西

function initMap()
{
    //...create new map here
    var infowindow;
    $('.business').each(function(el){
        //...get lat/lng
        var position = new google.maps.LatLng(lat, lng);
        var content = "contents go here";
        var title = "titleText";
        var openWindowFn;
        var closure = function(content, position){.
            openWindowFn = function()
            {
                if (infowindow)
                {
                    infowindow.close();
                }
                infowindow = new google.maps.InfoWindow({
                    position:position,
                    content:content
                });
                infowindow.open(map, marker);
            }
        }(content, position);
        var marker = new google.maps.Marker({
            position:position,
            map:map,
            title:title.
        });
        google.maps.event.addListener(marker, 'click', openWindowFn);
    }
}

在我的理解中,像这样使用闭包允许在函数声明时捕获变量及其值,而不是依赖全局变量。因此,当稍后调用openWindowFn,例如在第一个标记上时,contentposition变量具有在each()函数的第一次迭代期间所具有的值。

我不太确定openWindowFn如何在其范围内具有infowindow。我也不确定我是否做得对,但它可以工作,即使在同一页上有多个地图(每个地图都有一个打开的信息窗口)。

如果有人有任何见解,请评论。


0
如果您有多个标记,您可以使用这个简单的解决方案,在单击新标记时关闭先前打开的标记:
var infowindow = new google.maps.InfoWindow({
                maxWidth: (window.innerWidth - 160),
                content: content
            });

            marker.infowindow = infowindow;
            var openInfoWindow = '';

            marker.addListener('click', function (map, marker) {
                if (openInfoWindow) {
                    openInfoWindow.close();
                }
                openInfoWindow = this.infowindow;
                this.infowindow.open(map, this);
            });

0

当处理标记集群时,这个方法对我很有效。

var infowindow = null;

google.maps.event.addListener(marker, "click", function () {

        if (infowindow) {
            infowindow.close();
        }
        var markerMap = this.getMap();
        infowindow = this.info;
        this.info.open(markerMap, this);


    });

-1

在使用Google Maps时,我建议您尝试goMap jQuery插件。对于这种情况,您可以在创建标记时将hideByClick设置为true:

$(function() { 
    $("#map").goMap({ 
        markers: [{  
            latitude: 56.948813, 
            longitude: 24.704004, 
            html: { 
                content: 'Click to marker', 
                popup:true 
            } 
        },{  
            latitude: 54.948813, 
            longitude: 21.704004, 
            html: 'Hello!' 
        }], 
        hideByClick: true 
    }); 
}); 

这只是一个例子,它有很多功能可供使用,如分组标记和操作信息窗口。


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