vue--百度地图之离线地图

一、为什么有离线地图的存在

项目要在局域网内使用,也就是我们所说的在内网中使用,无法连接外网,所以需要开发离线地图功能。
(在看以下步骤前,先提示这个vue项目是vue-cli生成的,并且你需要确保你的在线地图是成功的,在线地图如果不知道怎么做,可以看我另一篇博客:在线地图

二、离线百度地图开发步骤

其实理解了离线百度地图,它的使用很简单,就是把在线百度地图的一些js文件下载到本地,再引用一下就可以啦

1、获取百度地图api的js代码

访问此链接
http://api.map.baidu.com/api?v=3.0&ak=biuHZmoAow03mjwThwt8f2whaf4mVdHf
这里特别注意一下,不是说直接用这个链接,这里只是给出了步骤,你需要将ak替换为你自己的(申请ak,点击这里),再进行如下步骤!!!
多说一句:申请ak时选择浏览器端哦!!!
打开会看到以下内容
在这里插入图片描述
在代码中找到红框中的内容
src=http://api.map.baidu.com/getscript?v=3.0&ak=biuHZmoAow03mjwThwt8f2whaf4mVdHf&services=&t=20191018171908
打开src中的链接,就可以获得百度地图api的js代码
在这里插入图片描述

2、js代码格式化,保存

代码格式化工具中,将上面的代码格式化,以便查看和修改。
2021-08-04 更新start:这里代码格式化可以直接在浏览器上进行,步骤如图
在这里插入图片描述
在这里插入图片描述
2021-08-04 更新end

然后新建js文件,将格式化后的代码粘贴进去,命名为baidu-api.js
再然后将此js文件放在vue项目中,我的放在了static下
在这里插入图片描述
最后,在vue项目的启动入口index.html的head中引入这个js文件
在这里插入图片描述

3、修改百度地图API文件

3.1 下载本地资源

所谓本地资源,就是在使用地图时需要用到的一些模块(module),比如图层类,标记类,控件类。
当你在地图中用到这些模块时,它会自动加载,因此我们需要先把这些模块的js文件下载下来,保存到本地。
这些模块有几十个之多,我们这里并不都存本地,而是用到哪个下载哪个,那么如何知道用到了哪个模块呢?

首先,在 baidu-api.js 文件中,用 &mod= 定位到下面的代码,然后加一行代码将用到的模块打印出来:

load: function(a, b, c) {
        var e = this.ob(a);
        if (e.Le == this.Bj.Mp) c && b();
        else {
            if (e.Le == this.Bj.bG) {
                this.UJ(a);
                this.hN(a);
                var f = this;
                f.fC == t && (f.fC = p, setTimeout(function() {
                    for (var a = [], b = 0, c = f.Qd.fn.length; b < c; b++) {
                        var e = f.Qd.fn[b],
                        n = "";
                        ia.oy.PJ(e) ? n = ia.oy.get(e) : (n = "", a.push(e + "_" + Bc[e]));
                        f.Qd.Cv.push({
                            zM: e,
                            rE: n
                        })
                    }
                    f.fC = t;
                    f.Qd.fn.length = 0;
                    
                    console.log("打印所需模块") 
                    console.log(a)//打印所需模块,这很重要!!!!!!
                    //console.log(f.TF.IP)//打印下面一行oa()里面的值,你需要通过这个链接下载模块--2021-08-04
                    // 0 == a.length ? f.DK() : oa(f.TF.IP + "&mod=" + a.join(","))
                    
                    //引用本地下载好的模块文件资源
                    if (a.length > 0) {
                        for (let i = 0; i < a.length; i++) {
                            let mf='./static/modules/'+a[i]+'.js'
                            //let mf = bmapcfg.home + 'modules/' + a[i] + '.js';
                            oa(mf);
                            console.log('加载模块文件:' + mf) //IE error
                        }
                    } else {
                        f.DK()//这里的函数DK(),根据你上面注释的那一行函数名而定
                    }
                },
                1));
                e.Le = this.Bj.xP
            }
            e.yu.push(b)
        }
    },

在这里插入图片描述

3.2 在baidu-api.js文件中,用Math.random()全局查找几次(我的是第5次),定位到以下代码位置:

(以下代码会在百度更新有些出入,但基本样式不变,找相似)

function oa(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 = L("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 = q
        },
        1)
    };

到此步,默认你已找到!!!
然后修改上面的代码,对HTTP拦截,不进行外部访问,只需在最开始添加一行:

if (/^http/.test(a)) return; //如果是调用外部资源就退出去

如下:

function oa(a, b) {
        //添加一行,对http拦截,不进行外部访问
        ///
        if (/^http/.test(a)) return; //如果是调用外部资源就退出去-2020.7.29
        //这里的a其实就是3.1步骤中oa(mf)里的mf,即你下载的模块路径-2021-08-04
        /
        
        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 = L("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 = q
        },
        1)
    };
3.3 设置引用本地资源路径

在baidu-api.js文件中,用url.domain.main_domain_cdn全局多查找几次,定位到下面的代码:

	D.Zt = window.HOST_TYPE || "0";
    D.url = D.s0[D.Zt];
    D.ep = D.url.proto + D.url.domain.baidumap + "/";
    D.nd = D.url.proto + ("2" == D.Zt ? D.url.domain.main_domain_nocdn.other: D.url.domain.main_domain_nocdn.baidu) + "/";
    D.oa = D.url.proto + ("2" == D.Zt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_nocdn.baidu) + "/";
    D.Yi = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + "/";

然后将
D.Yi = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + “/”;
改为 D.Yi = ‘’ ;
如下:

D.Zt = window.HOST_TYPE || "0";
    D.url = D.s0[D.Zt];
    D.ep = D.url.proto + D.url.domain.baidumap + "/";
    D.nd = D.url.proto + ("2" == D.Zt ? D.url.domain.main_domain_nocdn.other: D.url.domain.main_domain_nocdn.baidu) + "/";
    D.oa = D.url.proto + ("2" == D.Zt ? D.url.domain.main_domain_cdn.other[0] : D.url.domain.main_domain_nocdn.baidu) + "/";
    // D.Yi = D.url.proto + D.url.domain.main_domain_cdn.webmap[0] + "/";
    D.Yi = ''; 

然后,我们在需要使用地图的vue页面里,按照官方文档正常使用:

<template>
    <div id='MapBox'>
        <div  class='baiduMap' id='mapShow' ref="mapShow"></div>
    </div>
</template>
<script>
    export default {
        name:'baiduMap',
        data() {
            return{
                map: undefined,
                overView: undefined,
                marker: undefined,
                BMap: undefined,
            }
        },
        methods:{
            baiduMap(){
                debugger
                this.BMap = BMap;
                // 创建地图实例
                this.map = new BMap.Map("mapShow");
                // 创建点坐标
                let point = new BMap.Point(118.8035, 32.0658);
                //创建标注
                this.marker=new BMap.Marker(point);
                //缩略地图控件。
                this.overView=new BMap.OverviewMapControl({isOpen: true});
                //添加控件
                this.map.addControl(this.overView);
                //添加一个标注
                this.map.addOverlay(this.marker);
                // 初始化地图,设置中心点坐标和地图级别
                this.map.centerAndZoom(point, 12);
                //this.map.setCurrentCity("南京");
                //开启鼠标滚轮缩放
                this.map.enableScrollWheelZoom(true);
            }
        },
        mounted(){
            this.$nextTick(() => {
                this.baiduMap();
            })
        }
    }
</script>
<style>
    #MapBox {
        width: 100%;
        height: 100%;
        padding: 10px;
        position: relative;
    }
    /* 地图 */
    .baiduMap{
        height: 100%;
        width: 100%;
    }
    /* 去除地图上,左下字体标注 */
    .anchorBL{
        display:none;
    }
</style>

特别注意:如果你要在进入页面就初始化地图,最好像上面那样,放在 mounted 生命函数的 this.$nextTick(() => {})里,以确保地图容器 #mapShow 元素渲染完成,不然有可能因为初始化时地图容器还未渲染而报错:
在这里插入图片描述
刷新这个vue页,关注控制台,就能看到要实现这些地图功能所需要的模块名,是个数组集合,如下图,我这里需要以下17个模块:
在这里插入图片描述
通过下面的地址,只需要更换mod后面的值就可以找到需要的模块
下载api依赖模块的地址:点击这里下载依赖模块

2021-08-04 更新start
可能有些小伙伴通过上面的链接获取到的是空,这里更新下
在3.1步骤中,你可以看到这样一句话

0 == a.length ? f.DK() : oa(f.TF.IP + "&mod=" + a.join(","))

f.TF.IP打印出来,在后面加上&mod=,后面再加上你要下载的模块名称即可
在这里插入图片描述
2021-08-04 更新end

在static下建一个modules文件夹来存放即将下载的模块文件
然后新建以打印出的模块为命名的js,将通过地址搜索到的js复制到此js文件里。这样模块文件就下载好了。
在这里插入图片描述
现在就能成功加载模块资源了。
这里要注意路径问题,如果路径不对,找不到模块文件,会报错:
在这里插入图片描述

三、加载瓦片改为本地离线瓦片

离线瓦片可以理解为地图离线包,没有它,离线地图无法显示的。

1、瓦片嵌入在项目中的应用

1.1下载瓦片

太乐地图下载器----由于我电脑目前装不上这个软件,没有亲自下载,该过程暂时省略,后续会补上的哈
这里就先默认小伙伴们都已经拿到离线地图的图片资源了!!!
将所有瓦片文件夹整个复制到项目static/tiles目录下
在这里插入图片描述
因为离线的关系,在地图上进行缩放操作,想要缩放多少级,这些级别的瓦片必须都下载到本地。

1.2 瓦片配置文件

static目录下新建map_load.js文件,定义瓦片路径及瓦片格式即地图api的主目录:
在这里插入图片描述
我的瓦片是png格式的:

var bmapcfg={
    'imgext':'.png',//瓦片图的后缀  根据需要修改  一般.jpg  .png
    '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主目录,我这里打印出来为./static/

然后,在vue项目的启动入口index.html的head中引入map_load.js文件,要在baidu-api.js文件之前引入该配置文件:
在这里插入图片描述

1.3 修改baidu-api.js文件,加载瓦片路径

在 baidu-api.js 文件中,可以用 getTilesUrl 多找几次,定位到下面代码:

pe.getTilesUrl = function(a, b, c) {
        var e = a.x,
        a = a.y,
        f = Tb("normal"),
        g = 1,
        c = oe[c];
        this.map.lx() && (g = 2); 
        e = this.map.$e.fw(e,b).Zl; 
        return (ne[Math.abs(e + a) % ne.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi,"M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == A.fa.na ? "&color_dep=32&colors=50" : "") + "&udt=" + f + "&from=jsapi3_0").replace(/-(\d+)/gi,"M$1")
        
    };

修改如下:

pe.getTilesUrl = function(a, b, c) {
        var e = a.x,
        a = a.y,
        f = Tb("normal"),
        g = 1,
        c = oe[c];
        // this.map.lx() && (g = 2); 
        // e = this.map.$e.fw(e,b).Zl; 
        // return (ne[Math.abs(e + a) % ne.length] + "?qt=vtile&x=" + (e + "").replace(/-/gi,"M") + "&y=" + (a + "").replace(/-/gi, "M") + "&z=" + b + "&styles=" + c + "&scaler=" + g + (6 == A.fa.na ? "&color_dep=32&colors=50" : "") + "&udt=" + f + "&from=jsapi3_0").replace(/-(\d+)/gi,"M$1")
        //加载本地瓦片-2020.7.29
        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; //使用本地的瓦片
        //
    };

在这里插入图片描述
在这里可将调用瓦片的地址打印出来看看是否正确:
在这里插入图片描述
如果瓦片存在,且路径正确,就能正常显示地图了。

地图不能显示出来,是瓦片相关有问题
(看看是不是自己定的地图中心点坐标不在离线地图范围内,这时候会报错找不到图片)
地图的功能不能实现,是模块相关有问题
(看看模块资源是否齐全,关注打印区域,会有相关提示哦,ps:我最初没有加模块文件,客户端直接调试时谷歌浏览器都没报错,相关功能也全部正常;但放到nginx中就凉啦,打印区会提示需要相应的模块文件哒)

这里在 mp_load.js 里已经取到了主路径,可以将之前加载模块处代码修改成:

 if (a.length > 0) {
     for (let i = 0; i < a.length; i++) {
         // let mf='./static/modules/'+a[i]+'.js'
         let mf = bmapcfg.home + 'modules/' + a[i] + '.js';
         debugger 
         oa(mf);
         console.log('加载模块文件:' + mf) //IE error
     }
 } else {
     f.DK()
 }

到这里,离线地图就开发完成啦!

四、回答评论中常见的问题 2021-08-04 更新

1、Error in nextTick: “ReferenceError: BMap is not defined”

需要进行vue.config.js配置,详细见我另一篇文章:在线地图

2、地图瓦片对应不上,修改的getTilesUrl这个地方的a里面的x,y都是代表的什么

在这里插入图片描述
附上图给大家参考下,具体暂时没研究
在这里插入图片描述

3、Uncaught SyntaxError: Unexpected token ‘<’,

这里列一下小伙伴们出现并且已经解决的情况:
1、ak是你自己去百度官网申请的
2、申请ak时选择的是浏览器端
3、js等等的路径不正确也会有这个错
4、实在不行,参考问题5,还不行的话可能又是个新问题,可以一起讨论看看

4、下载的依赖模块js点开提示 We’re sorry but section doesn’t work properly without JavaScript enabled. Please enable it to continue.

这句话的意思是浏览器不支持javascript,但是不可能的,这不科学,所以一般都是js文件报错了,比如你想要获取js文件,但是响应头content-type却是html
解决方法参考:
这里需要看下加载的js文件资源名称是否为.js后缀,如果不是,找到加载该js路径的地方进行修改,详细步骤参考问题5

5、Uncaught SyntaxError: Unexpected token ‘<’ map_e1g5hy.js&v=3.0&seckey=undefined:1 ;

首先感谢这几位小伙伴,详细的报错引起了我的关注,因为我之前并没有出现这个问题,评论里有部分小伙伴在我提醒常见问题3中的解决方法后成功运行,我就一直以为是文件路径之类的问题,也没自己去试,近几天特别多小伙伴跟我提到这个问题,于是自己重新试了下,果然……就离谱啊,于是开始排查原因,这里省略一万只羊驼……
解决方法参考:
1、首先是这样的现象,报了一堆错,地图就展示了一张图,不能拖动也不能缩放,标记点也不出现(前提是这里的功能你都设置了),模块已经下载了,却还是打印,怎么刷新也不管用,如下
在这里插入图片描述
2、咱们点击map_e1g5hy.js&v=3.0&seckey=undefined:1会跳转到资源管理,现在我们会发现,明明是加载js,却显示index.html报错了,离谱
在这里插入图片描述
在这里插入图片描述
3、我们点击network,选择js,会发现content-type为html;点击preview,会出现问题4中描述的现象
在这里插入图片描述
在这里插入图片描述
4、我们点点其他js文件,发现js就要有js的样子嘛,map_e1g5hy.js&v=3.0&seckey=undefined:1你这整了一堆什么玩意儿,后缀还不是.js
在这里插入图片描述
在这里插入图片描述
5、这个其实就是我们加载模块时,模块资源加载路径出错了,我只要加载map_e1g5hy.js却给我整了map_e1g5hy.js&v=3.0&seckey=undefined:1,于是回到baidu-api.js,用 &mod=查找(步骤3.1),看到加载模块oa(mf),在下面最新的截图中是qa(mf),这里mf就是模块路径,一看写的对的呀,其实这不是我们的问题,嘎嘎,baidu-api.js会不定时更新,每个人都不一样,隔段时间也会不一样,大家看步骤吼(这里附上的图是最近会出问题的版本,跟上面步骤中的图参数会不一样,知道是这个函数就好),ctrl+点击qa,定位到qa(mf)函数,我们发现就是步骤3.2中限制调用外部资源的地方,然后我们发现官方给模块地址加上了"&v=3.0&seckey=" + pa这个玩意儿,其中pa是window.BMAP_SECKEY,最要命的是,这里的key还undefined!!!,对比之前的oa(mf)函数,我们发现的确是最新版本才出现的赋值,于是我们把它注释掉,再去刷新一下页面就ok啦!具体官方为什么会更新这一步,原因不详,后面知道了我再更新吧。
在这里插入图片描述
在这里插入图片描述

最后,这篇关于离线地图的步骤记录呢大部分都是参照vue集合离线百度地图这个作者的,再写一遍主要就是加深印象,也为了自己以后查阅方便,如有小伙伴不清楚怎么下载和使用太乐地图下载器,可以点这个链接查看哦
对于出现的问题,大家可以参考下,如有不当,欢迎指出,评论中出现新的问题,解决过后将及时更新

评论 70
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值