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
功能正在完成,并且在第一次单击标记时正确找到了内容。
尝试过:
查看了 the infobubble.js code 并将 console.logs 放在第 1231 行的任一侧:
google.maps.event.trigger(this, 'domready');
结果显示 domready 确实在动态函数开始之前被触发。
使用 infobubble disableAnimation: true
选项禁用动画 - 认为这可能会在调用 domready 后减慢 infobubble 加载 - 但它不起作用
添加了最多 3 秒的 setTimeout()
但这似乎没有帮助......而且这无论如何都是一个糟糕的 hack。
如何在第一次单击标记时加载动态内容?
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);
});
感谢观察 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 代码并完成它。
我正在尝试在 google 地图中添加动态内容 infobubble:
- 第一个标记点击一个空的信息气泡出现
- 在 SECOND 单击标记,加载正确的内容
根据 this answer,我在先前定义的 infobubble 对象上使用 domready
事件来启动加载动态内容的函数。
...尽管该答案中的 JS fiddle 具有误导性,因为 'dynamic' 内容实际上是在 domready
之前使用 new InfoBubble()
调用的 content
选项加载的
我在控制台中收到所有正确的信号,表明 domready
功能正在完成,并且在第一次单击标记时正确找到了内容。
尝试过:
查看了 the infobubble.js code 并将 console.logs 放在第 1231 行的任一侧:
google.maps.event.trigger(this, 'domready');
结果显示 domready 确实在动态函数开始之前被触发。使用 infobubble
disableAnimation: true
选项禁用动画 - 认为这可能会在调用 domready 后减慢 infobubble 加载 - 但它不起作用添加了最多 3 秒的
setTimeout()
但这似乎没有帮助......而且这无论如何都是一个糟糕的 hack。
如何在第一次单击标记时加载动态内容?
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);
});
感谢观察 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 代码并完成它。