为什么这个功能关闭不适用于谷歌地图api?

时间:2016-06-21 11:44:11

标签: javascript html google-maps google-maps-api-3

我正在创建一个页面,谷歌地图将使用许多标记进行渲染。我希望infowindow在点击时显示每个标记。为此,我必须在每个标记上添加click事件监听器。现在因为可以有数百个标记,我使用了for循环。那就是我必须为数百个标记添加事件监听器。为此,我使用了以下代码:

<!DOCTYPE html>
<html>
<head>
  <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
  <meta charset="utf-8">
  <title>Info windows</title>
  <style>
    html, body {
      height: 100%;
      margin: 0;
      padding: 0;
    }
    #map {
      height: 100%;
    }
    #first-tab {
      position: absolute;
      top: 10px;
      left: 10px;
      width: 100px;
      height: 100px;
      background-color: green;
    }
    #second-tab {
      position: absolute;
      top: 140px;
      left: 10px;
      width: 100px;
      height: 100px;
      background-color: red;
    }
    #third-tab {
      position: absolute;
      top: 300px;
      left: 10px;
      width: 100px;
      height: 100px;
      background-color: yellow;
    }

  </style>
</head>
<body>
  <script
  src="https://code.jquery.com/jquery-2.2.4.js"
  integrity="sha256-iT6Q9iMJYuQiMWNd9lDyBUStIq/8PuOW33aOqmvFpqI="
  crossorigin="anonymous"></script>
  <div id="map"></div>
  <div id="first-tab"></div>
  <div id="second-tab"></div>
  <div id="third-tab"></div>
  <script>

   function initMap() {

    var map = new google.maps.Map(document.getElementById('map'), {
      zoom: 4,
      center: {lat: -25.363, lng: 131.044}
    });

    var contentString = [];
    contentString[0] = '<div id="content">'+
    '<div id="siteNotice">'+
    '</div>'+
    '<h1 id="firstHeading" class="firstHeading">Uluru</h1>'+
    '<div id="bodyContent">'+
    '<p><b>Uluru</b>, also referred to as <b>Ayers Rock</b>, is a large ' +
    'sandstone rock formation in the southern part of the '+
    'Northern Territory, central Australia. It lies 335&#160;km (208&#160;mi) '+
    'south west of the nearest large town, Alice Springs; 450&#160;km '+
    '(280&#160;mi) by road. Kata Tjuta and Uluru are the two major '+
    'features of the Uluru - Kata Tjuta National Park. Uluru is '+
    'sacred to the Pitjantjatjara and Yankunytjatjara, the '+
    'Aboriginal people of the area. It has many springs, waterholes, '+
    'rock caves and ancient paintings. Uluru is listed as a World '+
    'Heritage Site.</p>'+
    '<p>Attribution: Uluru, <a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">'+
    'https://en.wikipedia.org/w/index.php?title=Uluru</a> '+
    '(last visited June 22, 2009).</p>'+
    '</div>'+
    '</div>';

    contentString[1] = '<div id="content">'+
    '<div id="siteNotice">'+
    '</div>'+
    '<h1 id="firstHeading" class="firstHeading">New York</h1>'+
    '<div id="bodyContent">'+
    '<p><b>New York</b>, also referred to as <b>Ayers Rock</b>, is a large ' +
    'sandstone rock formation in the southern part of the '+
    'Northern Territory, central Australia. It lies 335&#160;km (208&#160;mi) '+
    'south west of the nearest large town, Alice Springs; 450&#160;km '+
    '(280&#160;mi) by road. Kata Tjuta and Uluru are the two major '+
    'features of the Uluru - Kata Tjuta National Park. Uluru is '+
    'sacred to the Pitjantjatjara and Yankunytjatjara, the '+
    'Aboriginal people of the area. It has many springs, waterholes, '+
    'rock caves and ancient paintings. Uluru is listed as a World '+
    'Heritage Site.</p>'+
    '<p>Attribution: Uluru, <a href="https://en.wikipedia.org/w/index.php?title=Uluru&oldid=297882194">'+
    'https://en.wikipedia.org/w/index.php?title=Uluru</a> '+
    '(last visited June 22, 2009).</p>'+
    '</div>'+
    '</div>';



    var markers = [];

    locations = [{lat: -24.363, lng: 131.044}, {lat: -20.363, lng: 136.044}, {lat: -25.363, lng: 118.044}, {lat: -27.363, lng: 138.044}, {lat: -28.363, lng: 130.044}];
    titles = ['rock', 'Alpha', 'beta', 'gamma', 'neta'];


    for (var i = 2; i >= 0; i--) {
      markers[i] = new google.maps.Marker({
        position: locations[i],
        map: map,
        title: titles[i],
        mytype: 1
      });
    }

    for (var k = 4; k >= 3; k--) {
      markers[k] = new google.maps.Marker({
        position: locations[k],
        map: map,
        title: titles[k],
        mytype: 0
      });
    }

    var infowindow = new google.maps.InfoWindow();


          function myclosure(j) {
            return function() {
              infowindow.setContent(contentString[j]);
              infowindow.open(markers[j].get('map'), markers[j]);
            }
          }
          for (var j = 4; j >= 0; j--) {     
              markers[j].addListener('click', myclosure(j) );    
         }





    document.getElementById("second-tab").addEventListener('click', function() {

      for (var i = 2; i >= 0; i--) {
        markers[i].setMap(null);
      }
      for (var i = 4; i >= 3; i--) {
        markers[i].setMap(map);
      }
    });

    document.getElementById("first-tab").addEventListener('click', function() {
      for (var i = 4; i >= 3; i--) {
        markers[i].setMap(null);
      }
      for (var i = 2; i >= 0; i--) {
        markers[i].setMap(map);
      }
    });
    document.getElementById("third-tab").addEventListener('click', function() {
      for (var i = 4; i >= 0; i--) {
        markers[i].setMap(map);
      }

    });   

}
</script>
<script async defer
src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBga3chd-auBMGLGITc3rjact16mozcI4Q&callback=initMap">
</script>
</body>
</html>

我在包含事件侦听器的行中收到错误markers[j] isn't defined。如果不是循环,我手动执行以下操作:

              markers[0].addListener('click', function(){
               infowindow.setContent(contentString[0]);
              infowindow.open(markers[0].get('map'), markers[0]);
});

然后标记[0]上的infowindow工作正常。所以,

  

为什么myclosure功能不按预期工作?

编辑:有人建议在事件监听器中调用函数myclosure,我应该在一个立即调用的函数中使用事件监听器。但为什么我的方法不起作用?我在简单的dom元素上尝试了相同的方法并且它起作用了。这是我试过的代码:

var cont = document.getElementById("container");

function myclosure(i){
    return function(){
      alert("test" + i);
    }
  }

    for (var i = 1; i >= 0; i--) {
        cont.getElementsByTagName("div")[i].addEventListener("click",myclosure(i) );
    }
 * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }    
    #container {
      width: 100%;
      background-color: #ffff12;
    }
    .one, .two {
      padding: 10px;
      }
    .one {
      background-color: #777;
    }
    .two {
      background-color: #aaa;
    }
<div id="container">
      <div class="one">first</div>
      <div class="two">second</div>
    </div>

我使用的方法与谷歌地图使用的方法完全相同。

  

为什么此代码有效但谷歌地图代码无效?

4 个答案:

答案 0 :(得分:2)

在本节中

for (var j = 4; i >= 0; i--) { 
      markers[j].addListener('click', myclosure(j) );
}

您正在调用myclosure(),因此将返回的内容作为处理程序传递,而不是函数本身

for (var j = 4; i >= 0; i--) {
  (function(j) {
    markers[j].addListener('click', function() {
      myclosure(j);
    });
  })(j);
}

答案 1 :(得分:0)

我不知道这段代码的任何情况:

for (j in ) { 
          markers[j].addListener('click', myclosure(j) );
     }

可以运行。为了正常工作,它必须像

for (j in markers) { 
          markers[j].addListener('click', myclosure(j) );
     }

您可以使用其他几种方法来遍历数组。如果您遇到for..in的某些问题,可以使用forEach来设计循环数组。

答案 2 :(得分:0)

我发现了两件事。

  1. 范围绑定w.r.t addListener()调用循环:

    for (var j = 4; j >= 0; j--) {
      markers[j].addListener('click', function() {
         myclosure(j);
      });
    }
    

    您正在尝试访问eventHandler回调函数中的j只有当您点击标记时,才会执行此eventHandler。在这种情况下,当上下文发生变化时,j将为-1。为了解决这个问题,您可以采取以下措施。

    for (var j = 4; j >= 0; j--) {
      markers[j].idx = j;
      markers[j].addListener('click', (function() {
        myclosure(this.idx);
      }).bind(markers[j]));
    }
    

    将索引值作为属性添加到marker[j]并将其绑定到eventHandler。这将确保在运行时使用正确的值。但如果你不想改变marker[j],那么你也可以这样做:

    for (var j = 4; j >= 0; j--) {
      markers[j].addListener('click', (function() {
        myclosure(this);
      }).bind(j));
    }
    
  2. 上述更改仍然是让myclosure(j)工作的一半。 myclosure(j)返回一个永远不会被调用的函数:)要修复此问题,您的最终代码应与此类似。

    function myclosure(j) {
      return function() {
        infowindow.setContent(contentString[j]);
        infowindow.open(markers[j].get('map'), markers[j]);
      };
    }
    
    for (var j = 4; j >= 0; j--) {
      markers[j].addListener('click', (function() {
        myclosure(this)();
      }).bind(j));
    }
    

    为了使其更简单,您可以在上面重写为:

    function myclosure(j) {
      return function() {
        infowindow.setContent(contentString[j]);
        infowindow.open(markers[j].get('map'), markers[j]);
      };
    }
    
    for (var j = 4; j >= 0; j--) {
      markers[j].addListener('click', myclosure(j));
    }
    

    在这种情况下,我们在myclosure()为有效值的上下文中调用j。由于addListener()期望将function绑定为eventHandler,因此我们绑定myclosure(j)返回的函数。返回的函数将在标记点击时由myclosure(j)提供的范围内执行,其中j在循环中立即调用myclosure(j)时有效。

  3. 我希望澄清你对关闭执行的疑虑。

    Working JSFiddle我必须更改initMap()执行,就像在JSFiddle中一样,我无法将其作为map api调用的回调参数执行。

答案 3 :(得分:0)

如果您想使用JQuery,只需使用唯一ID属性为每个标记添加类,并使用类选择器添加click事件列表器。

`$(".marker").on("click",function(){
   var _id = $(this).attr('id');
   $(_id+"_infobox").show();
});`

现在使用id,您可以插入或打开该特定信息框。