最近在找最方便的年检地,但是有地址,却无法直观判断。各种地图应用也没有自定义多点显示。遂自己找了百度地图api写了个自定义多点显示的页面。碰到点坑,记录一下,分享一下。如果看官们觉的不错,或者有用,请留个爪印鼓励鼓励或者指出不足,也不枉我花时间写这么老半天。:)
环境:win10 1609 , 浏览器:Edge,ie,chrome
目录
坑一:跨域
坑二:BMap.Geocoder 和 BMap.LocalSearch
坑三:InfoWindow 信息窗口和 SearchInfoWindow 搜索信息窗口
坑四:异步回调与循环
坑一:跨域
api文档要求,引入格式为:
由于是本地用js写的一个页面,Edge直接不允许执行,在不改变安全配置的基础上,几乎无解,而且无论如何该页面,均会出错,最终放弃。
chrome的console中,一直出现错误
A parser-blocking, cross site (i.e. different eTLD+1) script, http://api.map.baidu.com/getscript?v=2.0&ak=你的key信息&services=&t=20181212102408, is invoked via document.write. The network request for this script MAY be blocked by the browser in this or a future page load due to poor network connectivity. If blocked in this page load, it will be confirmed in a subsequent console message. See https://www.chromestatus.com/feature/5718547946799104 for more details.
查了一下,是跨域错误,点进错误链接中看见这个src指向的脚本:
(function(){ window.BMap_loadScriptTime = (new Date).getTime(); document.write('');})();
由于用的document.write 重写脚本位置,造成chrome跨域错误。
搜索了一下网上信息,觉得最方便的就是直接将src改为脚本中的指向,但是发现t的值和别人教导的不同,遂采用自己获取到的src更改:
chrome中黄膏药一样的警告信息终于没了,清爽。
网上搜索的多点显示样例,用的是LocalSearch,搜索的另一个教程,用的是Geocoder 。
花了点功夫,找官方文档研究了一下,总结使用场景如下:
如果有详细地址,比如XX路XX弄XX号 ,建议使用Geocoder
如果是地标名称啥的,比如天安门,金茂大厦,使用LocalSearch
由于我写的东西,是有详细地址的,所以该使用Geocoder
一般教程文章中,使用的InfoWindow,样子及其土
想要百度自带的那种样式,
有个教程提到,注意用了不同的api,一开始,我只注意到,两个标准例子之间,第二个新增加了2个引用
天真的以为,只是引用的不同,改了半天的options
{
title : "百度大厦", //标题
width : 290, //宽度
height : 105, //高度
panel : "panel", //检索结果面板
enableAutoPan : true, //自动平移
searchTypes :[
BMAPLIB_TAB_SEARCH, //周边检索
BMAPLIB_TAB_TO_HERE, //到这里去
BMAPLIB_TAB_FROM_HERE //从这里出发
]
}
毛用没有,一直显示土样,翻了官方的api文档,这些options不在InfoWindowOptions中啊。火一大,2个例子文本直接放到BC中比较,才发现,狗日的,根本用的不是InfoWindow。
用的是BMapLib.SearchInfoWindow。这个SearchInfoWindow在百度地图api文档的类说明中根本没有,在百度API中才有。
百度地图api的demo中也不重点标注一下。
传送门:
纯文本的信息窗口 , 带检索功能的信息窗口
百度地图api的DEMO中,批量地址解析(传送门:批量地址解析),用的是setTimeout 400ms 全局变量实现的回调循环。样例中,用全局变量进行控制。复杂点的程序,这种控制比较难受。而且这种setTimeout,不能做到尽快完成。测试了一下,最低在100ms中,就会乱。
1、用同样的代码写到我的程序中,chrome调试的时候console总是出错,数组index溢出。发现Demo代码本身就不严谨,肯定会溢出。
function bdGEO(){
var add = adds[index];
geocodeSearch(add);
index++;
}
function geocodeSearch(add){
if(index < adds.length){
setTimeout(window.bdGEO,400);
}
index的最大值本来就是adds.length-1 ,index小于长度就继续search,最后值一定index溢出。
改为: index < adds.length -1
2、该程序主要用2个函数互相调用的方式,每搜索一次,就延迟400ms继续搜索。既然互相调用,直接在回调中加入调用得了。
为了防止某个地址堵死,仍旧保留setTimeout,改程序如下:
var t;
function bdGEO(){
var add = adds[index];
geocodeSearch(add);
index++;
}
function geocodeSearch(add){
if(index < adds.length-1){
//保留setTimeout的id
t=setTimeout(window.bdGEO,400);
}
myGeo.getPoint(add, function(point){
if (point) {
document.getElementById("result").innerHTML += index + "、" + add + ":" + point.lng + "," + point.lat + "";
var address = new BMap.Point(point.lng, point.lat);
addMarker(address,new BMap.Label(index+":"+add,{offset:new BMap.Size(20,-10)}));
}
//回调在400ms内,则直接调用。
clearTimeout(t);
window.bdGEO();
}, "合肥市");
}
速度快了一大截。但是仍然出现隐患(网络堵塞,回调时间超过400ms)。
3、这种解决方式非常不好,全局变量,难以控制。网上搜啊搜啊,在一个官方帖子中有人提到闭包。nnd涉及闭包从来都头疼。头疼也要看啊。瞅啊瞅啊,终于瞅懂一点,改造改造,直接用循环解决。
代码我就粗略写一下:
function bdGEO(){
for(var i=0 ; i< adds.length ; i ++){
var add = adds[i];
//闭包,想保留什么数据,直接填在括号里面,j,addr为参数名
(function(j,addr){
myGeo.getPoint(add,function(point){
if (point) {
document.getElementById("result").innerHTML += j + "、" + addr + ":" + point.lng + "," + point.lat + "";
var address = new BMap.Point(point.lng, point.lat);
addMarker(address,new BMap.Label(j+":"+addr,{offset:new BMap.Size(20,-10)}));
}
},"合肥市");
//注意 i,add 是外层的数据
})(i,add);
}
}
如果没必要保存顺序号,基本就完美了。如果要保存顺序号,可考虑事后排序问题,就不深入了。