Google Maps API v3 + jQuery UI Tabs存在的问题

70

使用 Google Maps API 在 jQuery UI 选项卡中渲染地图时,存在许多问题似乎已经广为人知。我看到类似问题的stackoverflow问答(例如这里这里),但那里提供的解决方案似乎仅适用于Maps API v2。我还查阅了其他参考资料,例如这里这里,以及通过谷歌搜索发现的几乎所有内容。

我一直在尝试将地图(使用API v3)放入jQuery选项卡中,但结果并不理想。我正在使用最新版本的所有内容(目前是jQuery 1.3.2,jQuery UI 1.7.2,不确定Maps版本)。以下是标记和javascript:

<body>
    <div id="dashtabs">
        <span class="logout">
            <a href="go away">Log out</a>
        </span>
        <!-- tabs -->
        <ul class="dashtabNavigation">
            <li><a href="#first_tab" >First</a></li>
            <li><a href="#second_tab" >Second</a></li>
            <li><a href="#map_tab" >Map</a></li>
        </ul>

        <!--  tab containers -->
        <div id="first_tab">This is my first tab</div>
        <div id="second_tab">This is my second tab</div>
        <div id="map_tab">
             <div id="map_canvas"></div>
        </div>
    </div>
</body>

并且

$(document).ready(function() {
    var map = null;
    $('#dashtabs').tabs();
    $('#dashtabs').bind('tabsshow', function(event, ui) {
        if (ui.panel.id == 'map_tab' && !map)
        {
            map = initializeMap();
            google.maps.event.trigger(map, 'resize');
        }
    });
});

function initializeMap() {
    // Just some canned map for now
    var latlng = new google.maps.LatLng(-34.397, 150.644);
    var myOptions = {
        zoom: 8,
        center: latlng,
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    return new google.maps.Map($('#map_canvas')[0], myOptions);
}

以下是我找到的在使用 Maps API v3 时可行/不可行的方法:

  • 在 jQuery UI Tabs 文档中描述的离线左侧技术(以及我引用的两个问题的答案)根本不起作用。实际上,最佳功能代码使用 CSS .ui-tabs .ui-tabs-hide { display: none; } 代替。
  • 唯一能让地图在选项卡中显示的方法是将 #map_canvas 的 CSS 宽度和高度设置为绝对值。将宽度和高度更改为 auto100% 会导致地图根本不显示,即使已经成功渲染(使用绝对宽度和高度)。
  • 我在 Maps API 之外找不到它有文档记录,但是 map.checkResize() 不再起作用。相反,您必须通过调用 google.maps.event.trigger(map, 'resize') 来触发一个调整大小的事件。
  • 如果地图未在绑定到 tabsshow 事件的函数内初始化,则地图本身将被正确呈现,但控件不会出现-大多数控件都只是普通的缺失。

所以,我有以下问题:

  • 是否有其他人有完成这项相同壮举的经验?如果有,您是如何找出实际可行的内容的,因为文档中提供的技巧对 Maps API v3 不起作用?
  • 使用 Ajax 加载选项卡内容如 jQuery UI 文档 中所述呢?我还没有机会尝试它,但我猜它会更破坏地图。让它起作用的机会有多大(或者根本不值得尝试)?
  • 如何使地图填充最大可能的区域?我想让它填充选项卡并适应页面调整大小,就像在 maps.google.com 上做的那样。但是,正如我所说,我似乎只能将绝对宽度和高度 CSS 应用于地图 div。

如果这篇文章冗长的话请见谅,因为这可能是 Maps API v3 + jQuery 选项卡的唯一文档。谢谢!


我发现谷歌地图群组在我使用jQuery + 地图时非常有帮助。不过,我并没有使用选项卡或jQuery UI。 - Jay
据我所知,所有的问题都是将地图放入jQuery UI选项卡中直接导致的。虽然地图组中的人可能有相关经验,但这似乎不是提问的合适场所。我可能会在其他地方寻求帮助。 - Matt Ball
很遗憾,他们在 API 部分非常有帮助,但无法在 jQuery 方面提供帮助。 - Jay
解决方案已经找到!!! :) http://stackoverflow.com/questions/12641798/google-maps-api-v3-maps-in-ui-tabs-are-cut/13380866#13380866 - Coder
17个回答

22

注意:本回答接受了一个无效的第三方编辑,其实质上替换了其内容,这是第三方编辑器不应该做的事情。然而,结果可能比原来更有用,因此现在将同时给出两个版本:


  • 2010年匿名作者Anon的原始版本,在经过Anon的一次编辑之后

    google.maps.event.trigger(map, 'resize'); map.setZoom( map.getZoom() );

建议使用此代码作为v3中checkResize()方法的替代品,具体内容请参见http://code.google.com/p/gmaps-api-issues/issues/detail?id=1448

呃——Google做得不好,没有小甜点。


  • 用户Eugeniusz Fizdejko在2012年进行了全面改写:

对我来说,当添加一个标记时它是有效的:

var marker = new google.maps.Marker({
    position: myLatlng,
    title:"Hello World!"
});

google.maps.event.addListener(map, "idle", function(){
    marker.setMap(map);
});

太棒了。我在一个jquery mobile / phonegap应用程序中遇到了这个问题,这个修复方法解决了我的问题! - Brade
1
这引导我得出答案,上面的链接code.google.com在几天前更新了引导标签和Google地图问题$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { google.maps.event.trigger(map, 'resize'); map.setZoom( map.getZoom() ); }) - NinjaKC

13

实际上,撤回我之前的答案。jQueryUI网站有答案,以下是:

为什么...

...我的滑块、谷歌地图、sIFR等在隐藏(非活动)选项卡中时无法工作?

任何需要进行一些尺寸计算以进行初始化的组件将无法在隐藏选项卡中工作,因为选项卡面板本身通过display: none进行隐藏,因此其中的任何元素都不会报告其实际宽度和高度(在大多数浏览器中为0)。

这里有一个简单的解决方法。使用左侧外移技术来隐藏非活动选项卡面板。例如,在样式表中,将类选择器“.ui-tabs .ui-tabs-hide”的规则替换为

.ui-tabs .ui-tabs-hide {
    position: absolute;
    left: -10000px;
}

对于Google地图,你还可以在选项卡显示后调整地图的大小,像这样:

$('#example').bind('tabsshow', function(event, ui) {
    if (ui.panel.id == "map-tab") {
        resizeMap();
    }
});

resizeMap()将在特定地图上调用Google Maps的checkResize()函数。


1
请编辑您的旧答案。此外,我指出了jQueryUI网站建议的离开左侧技术在这种情况下不起作用的事实。 - Matt Ball
抱歉 - 我不知道我可以编辑现有的评论。一直在博客上,我习惯于认为“一旦我说出来,就无法收回。”我只能告诉你的是,在此页面上,我的地图/街景在选项卡中完美运行:http://jackying.brixwork.com/showlisting.php/63/1701-388-Drake-Street-False-Creek-North-Vancouver-我能做的最好的事情就是向您展示代码,也许您可以进行比较并查看缺少/不同之处... 直到我发现我发布的解决方案,我的街景才没有工作了几天。 - jeffkee
#example 是指什么?是地图还是选项卡的ID?resizeMap() 是用于地图的V3函数吗? - bo-oz

12

只需重新定义隐藏选项卡的CSS类:

.ui-tabs .ui-tabs-hide {
    position: absolute !important;
    left: -10000px !important;
    display:block !important;
}

如果您没有生成G地图,则可以进行良好的修复-只需将on("click")添加到重置选项卡div的CSS即可。 - Q Studio

9

以下是您可以为Google Maps v3做的事情:

google.maps.event.addListenerOnce(map, 'idle', function() {
    google.maps.event.trigger(map, 'resize');
    map.setCenter(point); // be sure to reset the map center as well
});

我不确定空闲事件应该如何有帮助。即使它被触发,如果渲染在用户决定拖动并变得空闲之前仍然混乱,那么它有什么用处呢?调整大小在选项卡显示事件或超时/间隔的上下文中是有用的。 - computrius

4

当选项卡显示后,我加载地图。

这种方法有些取巧,但对我很有效。只需将地图iframe的URL存储在iframes rel属性中,如下所示:

<iframe width="490" height="300" rel="http://maps.google.com/maps?f=q&amp;source=s..."></iframe>

这个事件将会把iframe的src属性设置为rel内部的url。
        $("#tabs").tabs({
            show:function(event, ui) {
                var rel = $(ui.panel).find('iframe').attr('rel');
                $(ui.panel).find('iframe').attr('src',rel);
            }
        });

好的,你是怎么从iframe中获取经度和纬度坐标的? - Tony

4
这并不能回答你所有的问题,但我已经让它工作了,而且其他答案都缺少一个重要的东西——当你用“resize”事件重新绘制地图时,你会失去地图居中的位置。因此,如果你的地图居中于某个位置,你还需要使用setCenter来更新地图的中心。

另外,你不想每次触发选项卡更改时都初始化地图,因为这样不够高效,可能会导致额外的地理编码。首先,你需要保存你的中心位置,可以是静态的纬度/经度,或者如果进行地理编码,可能看起来像这样:

var address = "21 Jump St, New York, NY"; 
var geocoder = new google.maps.Geocoder();    
var myOptions = {
  zoom: 16,      
  mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);

var center;

geocoder.geocode( { 'address': address}, function(results, status) {
  if (status == google.maps.GeocoderStatus.OK) {        
    center = results[0].geometry.location;
    map.setCenter(center);
    var marker = new google.maps.Marker({
        map: map, 
        position: results[0].geometry.location
    });
  } else {
    alert("Geocode was not successful for the following reason: " + status);
  }
});

然后
$("#tabs").tabs();

$('#tabs').bind('tabsshow', function(event, ui) {
    if (ui.panel.id == "mapTab") {
        google.maps.event.trigger(map, "resize");
        map.setCenter(center);   // Important to add this!      
    }
});

其中'mapTab'是您的mapTab的ID,'map'是您的地图对象的变量名称。


1
通过将其绑定到选项卡单击事件,触发地图调整大小的这种方法也适用于 Twitter Bootstrap 选项卡 :) 在我看来,您的解决方案是最好的。 - haxxxton

2
请确保在初始化选项卡的片段之前调用初始化地图的代码。
我唯一的困扰是单击地图选项卡会使浏览器跳转到地图并且它会打破jQuery放置在主选项卡容器周围的默认边框。我为地图选项卡的a标签添加了一个返回false的onclick调用来处理第一个问题,并在主选项卡div上添加了一个简单的border-size: 0来处理第二个问题。
所有这些对我都有效。
祝你好运!

1

我也遇到了这个问题,我是通过 AJAX 加载地图的。

似乎百分比的问题与面板没有设置大小有关(包含加载标记的面板)。

在创建选项卡时使用以下代码对我很有帮助:

$("#mainTabs").tabs({'show': function(event, ui){
  $(ui.panel).attr('style', 'width:100%;height:100%;');
  return true;
 }});

1

我已经在每个论坛上搜索了答案...他们都说要使用

map.checkResize()

解决方案...似乎没有什么作用...然后我...为什么不在标签显示时初始化标签呢,所以我使用了这个方法。

$("#servicesSlider ").tabs({        
                //event: 'mouseover'
            fx: { height: 'toggle', opacity: 'toggle'},
            show: function(event, ui) {
                  if (ui.panel.id == "service5") {
                      $(ui.panel).css("height","100%")
                    initialize()
                    }}
            });

"

"service5"是我的选项卡ID,它包含了我使用的Google Map v3。

希望这对您有用!

"

这对我很有用,非常简单和优雅。我尝试了其他解决方案,但我想因为我的设置与上面的示例不同,所以它没有起作用(特别是resize方法调用)。但是这个有效,谢谢! - John Contarino
我发现使用 activate 要比 show 更好。我不确定为什么,但是 show 似乎会冻结我的选项卡并且不允许它再次折叠。 - Benjamin

1
嘿,大家好,这段代码可以修复错误,但在IE浏览器上不起作用。经过反复搜索,我发现我们必须添加以下行,这样一切就完美了:
< !--[if IE]>
< style type="text/css">
.ui-tabs .ui-tabs-hide { position: relative; }
< /style>
< ![endif]-->

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