Google Maps报错map.fitBounds() is not a function问题求助
问题排查:
map.fitBounds() is not a function 错误及地图空白问题 问题现象
加载页面时触发map.fitBounds() is not a function错误,地图时而显示空白、时而正常,首次加载通常能正常显示,无法定位代码问题。
原始代码
全局JavaScript部分
let _locations = []; var elenco; google.maps.visualRefresh = true; var slider, infowindow = null; var bounds = new google.maps.LatLngBounds(); var current = 0; var map = 0; var icons = { //'default': '/assets/img/marker.png' }; function showMap() { infowindow.close(); if (!map.slide) { return; } var next, marker; if (_locations.length == 0) { return } else if (_locations.length == 1) { next = 0; } if (_locations.length > 1) { do { next = Math.floor(Math.random() * _locations.length); } while (next == current) } current = next; marker = _locations[next]; setInfo(marker); //infowindow.open(map, marker); } function initialize() { var bounds = new google.maps.LatLngBounds(); var mapOptions = { zoom: 7, center: new google.maps.LatLng(42.4053848, 12.4276547), scrollwheel: false, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById('map'), mapOptions); map.slide = true; //setMarkers(map, _locations); infowindow = new google.maps.InfoWindow({ content: "loading..." }); google.maps.event.addListener(infowindow, 'closeclick', function () { infowindow.close(); }); slider = window.setTimeout(showMap, 3000); } function setInfo(marker) { var content = '<div class="profile-widget" style="width: 100%; display: inline-block;">' + '<div class="doc-img">' + '<a href="' + marker.profile_link + '" tabindex="0" target="_blank">' + '<img class="img-fluid" alt="' + marker.doc_name + '" src="' + marker.image + '">' + '</a>' + '</div>' + '<div class="pro-content">' + '<h4 class="text-center">' + '<a href="' + marker.profile_link + '" tabindex="0">' + marker.doc_name + '</a>' + '</h4>' + '<ul class="available-info pt-5">' + '<li><i class="fas fa-map-marker-alt"></i> ' + marker.address + ' </li>' + '</ul>' + '</div>' + '</div>'; infowindow.setContent(content); } function setMarkers(map, markers) { for (var i = 0; i < markers.length; i++) { var item = markers[i]; var latlng = new google.maps.LatLng(item.lat, item.lng); var marker = new google.maps.Marker({ position: latlng, map: map, doc_name: item.doc_name, address: item.address, speciality: item.speciality, profile_link: item.profile_link, animation: google.maps.Animation.DROP, icon: icons[item.icons], image: item.image }); bounds.extend(marker.position); markers[i] = marker; google.maps.event.addListener(marker, "click", function () { setInfo(this); infowindow.open(map, this); window.clearTimeout(slider); }); } map.fitBounds(bounds); google.maps.event.addListener(map, 'zoom_changed', function () { if (map.zoom > 16) map.slide = false; }); // Add a marker clusterer to manage the markers. new markerClusterer.MarkerClusterer({ markers, map }); } google.maps.event.addDomListener(window, 'load', initialize);
jQuery 数据请求部分
$(document).ready(function () { $.ajax({ url: "?handler=ElencoStrutture", type: "POST", beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, data: elenco, contentType: "application/json; charset=utf-8", success: function (data) { //console.error(data.ElencoStrutture); _locations = data.ElencoStrutture; setMarkers(map, _locations); slider = window.setTimeout(showMap, 3000); //alert("done ELENCO STRUTTURE"); } }); });
问题根源
- 执行顺序冲突:
$(document).ready会在DOM加载完成后立即触发ajax请求,但initialize函数要等window.load(所有资源包括谷歌地图脚本加载完成)才执行。如果ajax请求先完成,此时map还是初始值0(不是谷歌地图实例),调用map.fitBounds()就会报错。 - 全局变量污染:全局定义的
bounds与initialize内的局部bounds重名,且setMarkers使用全局bounds,多次调用时bounds会累积旧数据,导致地图视野异常。 - 原始数据被篡改:
setMarkers里将markers[i] = marker,把原始地址数据替换成了Marker实例,若多次调用setMarkers,会因无法读取item.lat/item.lng导致标记创建失败。
修复方案及修改后代码
修改后完整代码
let _locations = []; var elenco; google.maps.visualRefresh = true; var slider, infowindow = null; var current = 0; var map = null; // 初始化为null,语义更清晰 var icons = { //'default': '/assets/img/marker.png' }; function showMap() { if (!infowindow || !map?.slide) return; infowindow.close(); if (_locations.length === 0) return; let next = _locations.length === 1 ? 0 : null; if (_locations.length > 1) { do { next = Math.floor(Math.random() * _locations.length); } while (next === current); } current = next; const marker = _locations[next]; setInfo(marker); } function initialize() { const mapOptions = { zoom: 7, center: new google.maps.LatLng(42.4053848, 12.4276547), scrollwheel: false, mapTypeId: google.maps.MapTypeId.ROADMAP }; map = new google.maps.Map(document.getElementById('map'), mapOptions); map.slide = true; infowindow = new google.maps.InfoWindow({ content: "loading..." }); google.maps.event.addListener(infowindow, 'closeclick', () => infowindow.close()); // 地图初始化完成后再加载数据,保证map实例存在 loadLocations(); } function setInfo(marker) { const content = ` <div class="profile-widget" style="width: 100%; display: inline-block;"> <div class="doc-img"> <a href="${marker.profile_link}" tabindex="0" target="_blank"> <img class="img-fluid" alt="${marker.doc_name}" src="${marker.image}"> </a> </div> <div class="pro-content"> <h4 class="text-center"> <a href="${marker.profile_link}" tabindex="0">${marker.doc_name}</a> </h4> <ul class="available-info pt-5"> <li><i class="fas fa-map-marker-alt"></i> ${marker.address}</li> </ul> </div> </div> `; infowindow.setContent(content); } function setMarkers(map, locationData) { const bounds = new google.maps.LatLngBounds(); // 每次调用创建新的bounds,避免累积 const markers = []; // 用新数组存Marker,不修改原始数据 for (const item of locationData) { const latlng = new google.maps.LatLng(item.lat, item.lng); const marker = new google.maps.Marker({ position: latlng, map: map, doc_name: item.doc_name, address: item.address, speciality: item.speciality, profile_link: item.profile_link, animation: google.maps.Animation.DROP, icon: icons[item.icons], image: item.image }); bounds.extend(marker.position); markers.push(marker); google.maps.event.addListener(marker, "click", function () { setInfo(this); infowindow.open(map, this); window.clearTimeout(slider); }); } // 有标记时再调用fitBounds,避免空范围报错 if (locationData.length > 0) map.fitBounds(bounds); google.maps.event.addListener(map, 'zoom_changed', () => { if (map.zoom > 16) map.slide = false; }); new markerClusterer.MarkerClusterer({ map, markers }); } function loadLocations() { $.ajax({ url: "?handler=ElencoStrutture", type: "POST", beforeSend: function (xhr) { xhr.setRequestHeader("XSRF-TOKEN", $('input:hidden[name="__RequestVerificationToken"]').val()); }, data: elenco, contentType: "application/json; charset=utf-8", success: function (data) { _locations = data.ElencoStrutture; setMarkers(map, _locations); slider = window.setTimeout(showMap, 3000); }, error: (xhr, status, error) => { console.error("加载位置数据失败:", error); } }); } google.maps.event.addDomListener(window, 'load', initialize);
关键修复点
- 保证地图优先初始化:把ajax请求移到
initialize函数内执行,确保调用setMarkers时map已经是谷歌地图实例。 - 隔离变量作用域:在
setMarkers内部创建bounds,避免全局变量污染和旧数据累积。 - 保留原始数据:用新数组存储Marker实例,不修改
_locations,防止多次调用时数据类型错误。 - 增加边界判断:只有存在标记时才调用
fitBounds,避免空范围导致的异常。 - 添加错误处理:给ajax请求增加error回调,方便排查数据加载问题。
内容的提问来源于stack exchange,提问作者Fabio
相关产品推荐
相关产品推荐

