一、需求场景
所谓离线,大概都是项目在内网中使用,无法连接外网,所以需要开发离线地图功能。
在看以下步骤前,先提示这个vue项目是vue-cli生成的
二、开发步骤
1、通过API下载百度接口JS
打开会看到以下内容
在代码中找到src=http://api.map.baidu.com/getscript?v=3.0&ak=biuHZmoAow03mjwThwt8f2whaf4mVdHf&services=&t=20191018171908
打开src里的链接,就可以获得百度api的js代码
2、js代码清洗,保存
在在线JSON校验工具,将上面的代码,格式化,以便下面查看与修改。
然后新建js文件,将格式化后的代码粘贴进去,命名为baidu-api.js
再然后将此js文件放在vue项目中,我的放在了static/js下
最后,在vue项目的启动入口index.html的head中引入这个js
3、修改API文件
3.1、在baidu-api.js文件中,用Math.random()全局查找几次,定位到以下代码位置:
(以下代码会在百度更新有些出入,但基本样式不变,找相似)
function pa(a, b) {
if (b) {
var c = (1E5 * Math.random()).toFixed(0);
D._rd["_cbk" + c] = function(a) {
b && b(a);
delete D._rd["_cbk" + c]
};
a += "&callback=BMap._rd._cbk" + c
}
var e = O("script", {
type: "text/javascript"
});
e.charset = "utf-8";
e.src = a;
e.addEventListener ? e.addEventListener("load", function(a) {
a = a.target;
a.parentNode.removeChild(a)
}, t) : e.attachEvent && e.attachEvent("onreadystatechange", function() {
var a = window.event.srcElement;
a && ("loaded" == a.readyState || "complete" == a.readyState) && a.parentNode.removeChild(a)
});
setTimeout(function() {
document.getElementsByTagName("head")[0].appendChild(e);
e = s
}, 1)
};
到此步,默认你已找到!!!
然后修改上面的代码,对HTTP拦截,不进行外部访问,只需在最开始添加一行:
if (/^http/.test(a)) return;
就是如下样式
function pa(a, b) {
//////
if (/^http/.test(a)) return; // !!!!!这里加判断,如果是调用外部资源就退出去
//////
if (b) {
var c = (1E5 * Math.random()).toFixed(0);
D._rd["_cbk" + c] = function(a) {
b && b(a);
delete D._rd["_cbk" + c]
};
a += "&callback=BMap._rd._cbk" + c
}
var e = O("script", {
type: "text/javascript"
});
e.charset = "utf-8";
e.src = a;
e.addEventListener ? e.addEventListener("load", function(a) {
a = a.target;
a.parentNode.removeChild(a)
}, t) : e.attachEvent && e.attachEvent("onreadystatechange", function() {
var a = window.event.srcElement;
a && ("loaded" == a.readyState || "complete" == a.readyState) && a.parentNode.removeChild(a)
});
setTimeout(function() {
document.getElementsByTagName("head")[0].appendChild(e);
e = s
}, 1)
};
3.2、设置引用本地资源路径
在baidu-api.js文件中,用url.domain.main_domain_cdn.baidu[0]
全局多查找几次,定位到下面的代码:
D.Nt = window.HOST_TYPE || "0";
D.url = D.I_[D.Nt];
D.Uo = D.url.proto + D.url.domain.baidumap + "/";
D.Cd = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_nocdn.other : D.url.domain.main_domain_nocdn.baidu) + "/";
D.oa = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_cdn.baidu[0]) + "/";
D.Ri = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + "/";
然后将
D.Ri = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + "/"
改为 D.Ri = '' :
如下样式:
D.Nt = window.HOST_TYPE || "0";
D.url = D.I_[D.Nt];
D.Uo = D.url.proto + D.url.domain.baidumap + "/";
D.Cd = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_nocdn.other : D.url.domain.main_domain_nocdn.baidu) + "/";
D.oa = D.url.proto + ("2" == D.Nt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_cdn.baidu[0]) + "/";
///////
D.Ri = '';
///////
D.Yh = function(a, b) {
var c, e, b = b || "";
3.3、下载本地资源
所谓本地资源,就是在使用地图时需要用到的一些模块(module),比如图层类,标记类,控件类。
当你在地图中用到这些模块时,它会自动加载,因此我们需要先把这些模块的js文件下载下来,保存到本地。
这些模块有几十个之多,我们这里并不都存本地,而是用到哪个下载哪个,那么如何知道用到了哪个模块呢?
首先,在 baidu-api.js 文件中,用 &mod= 定位到下面的代码,然后加一行代码将用到的模块打印出来:
load: function(a, b, c) {
var e = this.lb(a);
if (e.Ke == this.tj.Bp) c && b();
else {
if (e.Ke == this.tj.BF) {
this.nJ(a);
this.EM(a);
var f = this;
f.OB == t && (f.OB = p, setTimeout(function() {
for (var a = [], b = 0, c = f.Pd.Vm.length; b < c; b++) {
var e = f.Pd.Vm[b],
n = "";
ja.Zx.iJ(e) ? n = ja.Zx.get(e) : (n = "", a.push(e + "_" + Tb[e]));
f.Pd.qv.push({
VL: e,
UD: n
})
}
f.OB = t;
f.Pd.Vm.length = 0;
//!!!!!!!!!!!!!!!!!!!!
console.log("打印所需模块");
console.log(a); //!!!!!打印所需模块,这很重要
//!!!!!!!!!!!!!!!!!!!!
//0 == a.length ? f.XJ() : pa(f.tF.$O + "&mod=" + a.join(","))
//////引用本地下载好的模块文件资源
if( a.length > 0 ){
for(let i=0; i
然后,我们在需要使用地图的vue页面里,按照官方文档正常使用:
特别注意:如果你要在进入页面就初始化地图,最好像上面那样,放在 mounted 生命函数的 this.$nextTick(() => {})里,以确保地图容器 #mapShow 元素渲染完成,不然有可能因为初始化时地图容器还未渲染而报错:
从上继续:
刷新这个vue页,关注控制台,就能看到要实现这些地图功能所需要的模块名,是个数组集合,如下图,我这里需要以下十一个模块:
下载api依赖模块的地址
http://api.map.baidu.com/getm...
通过上面的地址,只需要更换mod后面的值就可以找到需要的模块
然后在static下建一个modules文件夹来存放即将下载的模块文件
然后新建以打印出的模块为命名的js,将通过地址搜索到的js复制到此js文件里。这样模块文件就下载好了。
3.4、引用本地资源
在上面打印模块名的地方,做如下修改:
load: function(a, b, c) {
var e = this.lb(a);
if (e.Ke == this.tj.Bp) c && b();
else {
if (e.Ke == this.tj.BF) {
this.nJ(a);
this.EM(a);
var f = this;
f.OB == t && (f.OB = p, setTimeout(function() {
for (var a = [], b = 0, c = f.Pd.Vm.length; b < c; b++) {
var e = f.Pd.Vm[b],
n = "";
ja.Zx.iJ(e) ? n = ja.Zx.get(e) : (n = "", a.push(e + "_" + Tb[e]));
f.Pd.qv.push({
VL: e,
UD: n
})
}
f.OB = t;
f.Pd.Vm.length = 0;
//!!!!!!!!!!!!!!!!!!!!
console.log("打印所需模块");
console.log(a); //!!!!!打印所需模块,这很重要
//!!!!!!!!!!!!!!!!!!!!
//0 == a.length ? f.XJ() : pa(f.tF.$O + "&mod=" + a.join(","))
//////引用本地下载好的模块文件资源
if( a.length > 0 ){
for(let i=0; i
现在就能成功加载模块资源了。
这里要注意路径问题,如果路径不对,找不到模块文件,会报错:
三、加载瓦片改为本地离线瓦片
离线瓦片可以理解为地图离线包,没有它,离线地图无法显示的。
1、瓦片嵌入在项目中引用
1.1、下载瓦片
网上提供了水经注或者太乐地图下载器下载瓦片,介绍我用的太乐
太乐地图下载器
下载 -> 选择行政区划,选完了之后该区域就会出现ufo图标
找到存储目录:我这里下载了重庆12级的瓦片,所有的瓦片就存储在了12这个文件夹下
将所有瓦片文件夹整个复制到项目static/tiles目录下
你会发现除了下载了12级,还下载了9、10、11级,因为离线的关系,在地图上进行缩放操作到11级,但是如果没有11级的瓦片,地图就什么都不显示。所以如果想要缩放多少级,这些级别的瓦片必须都下载到本地。
1.2、瓦片配置文件
static目录下新建mp_load.js文件,定义瓦片路径及瓦片格式即地图api的主目录:
我们的瓦片是png格式的:
var bmapcfg = {
'imgext' : '.png', //瓦片图的后缀 根据需要修改,一般是 .png .jpg
'tiles_dir' : '', //普通瓦片图的地址,为空默认在tiles/ 目录
};
var scripts = document.getElementsByTagName("script");
var JS__FILE__ = scripts[scripts.length - 1].getAttribute("src"); //获得当前js文件路径
bmapcfg.home = JS__FILE__.substr(0, JS__FILE__.lastIndexOf("/")+1); //地图API主目录
然后在API文件之前引入该配置文件:
1.3、修改API文件加载瓦片路径
在 baidu-api.js 文件中,可以用 getTilesUrl 多找几次,定位到下面代码:
Hd.getTilesUrl = function(a, b, c) {
var e = a.x,
a = a.y,
f = Sb("normal"),
g = 1,
c = Gd[c];
this.map.Yw() && (g = 2);
e = this.map.oh.Uv(e, b).Ol;
return (Fd[Math.abs(e + a) % Fd.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == z.ga.ma ? "&color_dep=32&colors=50" : "") + "&udt=" + f).replace(/-(\d+)/gi, "M$1")
};
修改如下:
Hd.getTilesUrl = function(a, b, c) {
var e = a.x,
a = a.y,
f = Sb("normal"),
g = 1,
c = Gd[c];
// this.map.Yw() && (g = 2);
// e = this.map.oh.Uv(e, b).Ol;
// return (Fd[Math.abs(e + a) % Fd.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi, "M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == z.ga.ma ? "&color_dep=32&colors=50" : "") + "&udt=" + f).replace(/-(\d+)/gi, "M$1")
//////加载本地瓦片
let tdir = bmapcfg.tiles_dir.length>0?bmapcfg.tiles_dir:bmapcfg.home + "tiles";
console.log(tdir + "/" + b + "/" + e + "/" + a + bmapcfg.imgext);
return tdir + "/" + b + "/" + e + "/" + a + bmapcfg.imgext; // 使用本地的瓦片
//////
};
在这里可将调用瓦片的地址打印出来看看是否正确:
1.4、关于地图下载器
太乐
太乐地图下载器在没有付费的情况下,最高只能下载12级,而且文件数量有限制,也就是说如果你选择的区域很大,可能连12级都无法下载,比如这里,我要下载中国地图,只能下载到第8级:
但是,如果你买了vip,那就没有任何限制了,具体收费情况我没问
水经注
我没用水经注来说明,是因为水经注下载器,如果没有付费,下载不了瓦片。水经注的购买费用大概800元,买了后没有限制,一直可用。
瓦片文件大小
这是中国地图瓦片,可以看到第11级就1G了,16级1T,17级4T。如果你的地图需要带缩放功能,就吧这些大小累加,几T吧~~
--------------------------------------------特别注意------------------------------------------
作为一个技术猿,怎会花钱去买,所以经过不懈努力,找到了可以下载完整瓦片的地图下载器,作为题主,自然要拿出来分享,通过以下内容,到百度云下载即可:
https://pan.baidu.com/s/1Mxvf...
提取码:
ojji
如果可以帮助到你,麻烦小手点个赞,走一波爱心支持,小生在此谢过