Javascript 为什么不是';这个函数闭包是否适用于GoogleMapAPI?

Javascript 为什么不是';这个函数闭包是否适用于GoogleMapAPI?,javascript,html,google-maps,google-maps-api-3,Javascript,Html,Google Maps,Google Maps Api 3,我正在制作一个页面,谷歌地图将在该页面上显示许多标记。我希望单击时为每个标记显示infowindow。为此,我必须在每个标记上添加click事件侦听器。现在,因为可以有数百个标记,所以我使用了for循环。也就是说,我必须向数百个标记添加事件侦听器。为此,我使用了以下代码: <!DOCTYPE html> <html> <head> <meta name="viewport" content="initial-scale=1.0, user-scala

我正在制作一个页面,谷歌地图将在该页面上显示许多标记。我希望单击时为每个标记显示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>
然后标记[0]上的信息窗口可以正常工作。所以

为什么myclosure函数不能按预期工作

Edit:有人建议,与其在事件侦听器中调用函数
myclosure
,不如在立即调用的函数中使用事件侦听器。但是为什么我的方法不起作用呢?我在简单的dom元素上尝试了相同的方法,并且成功了。以下是我尝试的代码:

var cont=document.getElementById(“容器”);
函数myclosure(i){
返回函数(){
警报(“测试”+i);
}
}
对于(变量i=1;i>=0;i--){
cont.getElementsByTagName(“div”)[i].addEventListener(“单击”,MyClose(i));
}
*{
保证金:0;
填充:0;
框大小:边框框;
}    
#容器{
宽度:100%;
背景色:#ffff12;
}
.1、.2{
填充:10px;
}
.一{
背景色:#777;
}
.二{
背景色:#aaa;
}

第一
第二

我不知道在什么情况下该代码:

for (j in ) { 
          markers[j].addListener('click', myclosure(j) );
     }
我能跑。为了正确工作,它必须是

for (j in markers) { 
          markers[j].addListener('click', myclosure(j) );
     }
您还可以使用其他几种方法在数组中循环。如果遇到一些问题,您可以使用设计为通过阵列循环的

for (var j = 4; i >= 0; i--) { 
      markers[j].addListener('click', myclosure(j) );
}
您调用的是
myclosure()
,因此传递的是作为处理程序返回的内容,而不是函数本身

试一试

我注意到两件事

  • 作用域绑定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]));
    }
    
    将索引值作为属性添加到
    标记[j]
    ,并将其绑定到eventHandler。这将确保在运行时使用正确的值。但是如果您不想变异
    标记[j]
    ,那么您也可以这样做:

    for (var j = 4; j >= 0; j--) {
      markers[j].addListener('click', (function() {
        myclosure(this);
      }).bind(j));
    }
    
  • 以上更改仍然是使您的
    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));
    }
    
    在本例中,我们在
    j
    为有效值的上下文中调用
    myclosure()
    。由于
    addListener()
    希望将
    函数
    绑定为eventHandler,因此我们绑定
    myclosure(j)
    返回的函数。在单击标记时,返回的函数将在
    myclosure(j)
    提供的范围内执行,其中
    j
    由于在循环中立即调用
    myclosure(j)
    而有效

  • 我希望这能澄清你对关闭执行的怀疑


    我必须更改
    initMap()
    执行,因为在JSFIDLE中,我很难将其作为map api调用的回调参数执行。

    如果要使用JQuery,只需将类添加到具有唯一ID属性的每个标记中,然后使用类选择器添加click event listner

    `$(".marker").on("click",function(){ var _id = $(this).attr('id'); $(_id+"_infobox").show(); });` `$(“.marker”)。在(“单击”,函数(){ var_id=$(this.attr('id'); $(_id+“_infobox”).show(); });`
    现在使用id,您可以插入或打开特定的信息框。

    您可以修改代码中导致问题的独立部分吗?我不知道如何在JSFIDLE中添加google api脚本。您可以将整个代码保存为html文件并运行它。在测试您发布的整个代码时,我不会遇到任何错误。你直接试这个有什么问题吗?您可能没有发布完全相同的代码,但这一代码在Chrome和FF上似乎功能正常。信息窗口不会显示。我想让他们看。我发现错误
    标记[j]未定义
    。我现在也试过了。但它仍然不起作用。我甚至在
    myclosure(j)
    函数中添加了
    alert(j)
    ,只分配函数的定义?因为使用
    ()
    调用函数。你可以做
    addListener('click',myclosure)
    但是参数不是你想要的我做了这个小提琴,但是我不能添加google api键。你能在结尾添加这个脚本吗。我从未对(var j=4;j>=0;j--)使用过
    {markers[j].addListener('click',function(){myclosure(j);});}
    2。您链接的工作小提琴使用与我问题中相同的代码。3.似乎我的代码总是正确的;它现在在我的浏览器中工作。可能会出现一些后端或服务器问题。哦,天哪!Ye我在你的问题中注意到你已经在使用
    myclosure(j)
    call了。我很抱歉解释得那么详细,但我用你的小提琴代码只是为了解释我所做的更改。因此,
    标记[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));
    }
    
    `$(".marker").on("click",function(){ var _id = $(this).attr('id'); $(_id+"_infobox").show(); });`