google 地图 infobubble 动态内容未在首次点击标记时加载

google maps infobubble dynamic content not loading on first marker click

我正在尝试在 google 地图中添加动态内容 infobubble:
- 第一个标记点​​击一个空的信息气泡出现
- 在 SECOND 单击标记,加载正确的内容

根据 this answer,我在先前定义的 infobubble 对象上使用 domready 事件来启动加载动态内容的函数。
...尽管该答案中的 JS fiddle 具有误导性,因为 'dynamic' 内容实际上是在 domready 之前使用 new InfoBubble() 调用的 content 选项加载的

我在控制台中收到所有正确的信号,表明 domready 功能正在完成,并且在第一次单击标记时正确找到了内容。

尝试过:

如何在第一次单击标记时加载动态内容?

JS Fiddle here

备注:
- 对于 js fiddle 示例,我使用 $.get() 调用 - 因为在我的应用程序中,我使用 mustache 将模板加载到 infobubble
- 正在加载的示例内容与 $.get() 调用无关(是的,我可以在没有 $.get() 调用的情况下实现相同的效果)但我只是尝试使用类似的代码布局 + 时间自己申请

问题似乎是信息气泡的 open_ 方法(将在 open 方法中调用):

InfoBubble.prototype.open_ = function(opt_map, opt_anchor) {
  this.updateContent_();

  if (opt_map) {
    this.setMap(opt_map);
  }
  //............................
}

它首先调用方法updateContent_domready-事件将被触发)然后设置map。但是在设置 map-属性 之前不会将叠加层添加到地图中,内容是尚未附加到文档的 DocumentFragment/Node,所以 jQuery可能找不到。

可能的解决方案:

使用信息气泡的 content_-属性 作为 jQuery-选择器的上下文,那么内容是否已经附加到文档中并不重要

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

  google.maps.event.addListenerOnce(infoBubble,'domready',function () {

    var that=this;            
    //when we load the additional content asynchronously, 
    //make sure that it's the correct content we are loading
    var token=new Date().getTime()*Math.random();
    that.set('token',token);

    $.get('https://lh4.googleusercontent.com/-_Cox6aEnSkU/UQ_B0LK4khI/AAAAAAAAAzw/4H4dsWGPgeE/s150/go-button.png', function (myImage) {
      if(that.get('token')===token){
        $(".dialog",that.content_).html('<img id="theImg" src="https://goo.gl/phmzis" />');
      }     
        })

  });
  infoBubble.open(map, marker);
});

http://jsfiddle.net/doktormolle/aLtz76ym/

感谢观察 I've figured out the solution - which is indeed related to the placement of the domready event trigger in the infobubble.js 代码。

不幸的是,它当前位于 updateContent_() 函数中,该函数由 open_() 调用,在 setMap() 被调用之前 - 这意味着 domready 在 infoBubble 之前被触发添加到 DOM.

无法在 open_() 函数中的 setMap() 调用之后简单地添加 domready 触发器,因为 setMap() 是异步的...并且 setMap() 函数没有特定的回调。

但是,根据 documentation for OverlayView(此插件正在使用的内容),setMap() 函数会在调用 setMap() 后调用 onAdd() 函数使用有效的地图对象:

onAdd(): Implement this method to initialize the overlay DOM elements. This method is called once after setMap() is called with a valid map. At this point, panes and projection will have been initialized.

更简单地说:

In the onAdd() method, you should create DOM objects and append them as children of the panes.

因此我们应该在 onAdd() 函数中触发 domready 事件, infoBubble 附加到地图窗格后:

/**
 * On Adding the InfoBubble to a map
 * Implementing the OverlayView interface
 */
InfoBubble.prototype.onAdd = function() {
  if (!this.bubble_) {
    this.buildDom_();
  }

  this.addEvents_();

  var panes = this.getPanes();
  if (panes) {
    panes.floatPane.appendChild(this.bubble_);
    panes.floatShadow.appendChild(this.bubbleShadow_);
  }
  google.maps.event.trigger(this, 'domready');    // infobubble has now been added to DOM so we can fire `domready`
};

我创建了一个 pull-request for google to update the infobubble.js code 并解决了这个问题。

JS Fiddle 此处更新了代码(请参阅 javascript window 中的第 910 行以获得新的 domready 位置)
http://jsfiddle.net/goredwards/7r96we66/

备注:
- 我在旧的 domready 调用和正确的(更新的)domready 调用的 jsfiddle 中添加了时间戳 - 你会在 console.log 中看到它们 - 它大约需要 20 毫秒我的系统(会随系统速度变化)
- 它表明旧的 domready 确实在 infoBubble 被附加到窗格
之前触发 - 这给出了你需要在 domready 调用

中放置任何函数的最小值 setTimeout

如果您想使用没有修复的原始代码 - 和 setTimeout hack:http://jsfiddle.net/goredwards/xeL7dxye/
...您可以尝试 setTimeout 持续时间,看看最小值是多少 - 我在一台快速机器上降低到大约 5 毫秒。显然,您必须使用此 hack 在生产代码中采用 other 方式来应对最慢的机器(即,您将 setTimeout 持续时间设置为最大级别可以忍受 - 没有烦恼 ~150-250ms - 甚至可以覆盖你最慢的系统)。
... 或者您可以复制并更新 infobubble.js 代码并完成它。