赞
踩
在工作中遇到的项目场景。由于项目有国内和国外用户,对地图的需求不同,国内人士倾向于使用百度,高德等地图;而国外用户则更多的使用Here地图。而很麻烦的是,百度,腾讯等地图对国外的支持并不友好,很多地方都是模糊的。Here地图确刚好相反,由于天朝的种种原因,导致Here地图在国内的地图是无法访问的。基于这种情况,就需要项目本身支持多种地图的切换。这个demo只是基于 百度地图 以及Here地图之间的相互切换,不过我本身对代码做了拓展,想要支持别的地图,按照我的注释添加对应的地图引擎即可。(第一次写博客,不足之处希望大家多多指教,一个前端菜鸡)
这部分没啥说的啦,抄起键盘就是一顿CV。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>地图引擎测试</title> <style> #MapEngineContant{ width: 640px; height: 640px; } </style> </head> <body> <!-- 可显示地图列表 --> <select id="MapEngineList"> </select> <!-- 显示地图区域 --> <div id="MapEngineContant"></div> <script src="./MapEngine.js"></script> </body> </html>
在MapEngine.js下我准备了一些常量用于引擎本身,当然,这些常量我都已经抽取出来了,方便外部直接赋值(这只是一个测试实例,我并没有使用模块化开发,需要模块化开发的完整实例,可以联系我)
//默认地图引擎,由系统设置提供 //具体数据猜测应该放在redux仓库中 通过模块导入 const defaultMapEngine = 'BaiduMap' //可支持的地图引擎 //随便写的几个,想要地图拓展就在这里加就好了,目前可用的只有百度和Here const MapEngineList = { BaiduMap: '百度地图', HereMap: 'Here地图', TencentMap: '腾讯地图', GaodeMap: '高德地图', BinyingMap: '必应地图' } //起始坐标点,外部参数,(坐标定位暂时不处理,需要根据算法重新换算) const defaulePoint = { x: 0, y: 0 }
工作中我的设定是,可支持的地图引擎由后台存放,返回前端。如果没有明确的要求,这里也是可以写死的
//根据 MapEngineList 来渲染页面的地图选择选项 //MapList -> Object 可支持的地图引擎 function RenderMapList(MapList) { //获取地图显示列表 let MapShowList = document.getElementById('MapEngineList') //渲染地图显示列表 for (Mapitem in MapList) { let MapListNode = document.createElement('option') let text = document.createTextNode(`${MapList[Mapitem]}`) MapListNode.appendChild(text); MapShowList.appendChild(MapListNode) //默认显示 默认加载项 if (`${Mapitem}` === defaultMapEngine) MapListNode.setAttribute('selected', 'selected') } }
这个函数是实现功能的核心函数,用于动态向html中添加脚本,用的思路是在网上查找到的文档,核心思路就是动态添加一个script元素,然后修改他的src属性达到动态加载的目的。但是这里有一个坑,那就是同步加载和异步加载的问题,需要根据具体的使用场景来实现,我在这里采用了回调函数的方式(我的代码拷贝自此处,没联系到本人,冒昧引用,如有侵犯,联系我删除哦!!)
https://blog.csdn.net/u010289111/article/details/62892623
//动态加载script //url -> String 资源加载地址 function loadScript(url, callback) { let script = document.createElement('script') script.type = 'text/javascript' if (script.readyState) { //IE浏览器 script.onreadystatechange = function () { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; callback() } }; } else { //标准浏览器 script.onload = function () { callback() }; } script.src = url document.getElementsByTagName('head')[0].appendChild(script) }
使用switch case分支语句对需要进行渲染选项进行基础渲染,注意哦,这里只是基础渲染,没有附加功能的(在我的项目中,我这里是需要后台数据配合的,为了公用,我把他抽取处理了一下,只会加载基础的地图部分,最多就是消除一下这个水印了,我也不知道这个犯法不,哈哈,不过一个应用中就算用到了这个地图,光溜溜的显示一个百度和here的logo确实看着怪怪的。对应的密钥,手令。大家就自己去申请了,这个简单哦。)
//根据参数加载对应地图(并去掉对应的水印) //MapEngine -> String 地图引擎 function LoadMap(MapEngine) { switch (MapEngine) { //Here地图 case 'HereMap': loadScript('http://js.api.here.com/v3/3.0/mapsjs-core.js', function () { loadScript('http://js.api.here.com/v3/3.0/mapsjs-service.js', function () { removeMapArea() console.log('Here地图加载OK'); let platform = new H.service.Platform({ 'app_id': 'Here地图开发者ID', 'app_code': 'Here地图开发者手令' }); let defaultLayers = platform.createDefaultLayers() new H.Map( MapEngineContant, defaultLayers.normal.map, { zoom: 14, center: { lat: 52.5, lng: 13.4 } }); //去除相关水印 let HereMaker = document.querySelector('#MapEngineContant>div:last-child>div:last-child') HereMaker.parentNode.removeChild(HereMaker) }) }) break; //百度地图 case 'BaiduMap': loadScript('http://api.map.baidu.com/api?v=2.0&ak=百度地图开发者密钥', function () { loadScript('http://api.map.baidu.com/getscript?v=2.0&ak=百度地图开发者密钥&services=&t=20190102133327', function () { removeMapArea() console.log('百度地图加载OK'); // 创建地图实例 let map = new BMap.Map('MapEngineContant') // 创建点坐标 let point = new BMap.Point(116.404, 39.915) // 初始化地图,设置中心点坐标和地图级别 map.centerAndZoom(point, 22) //开启鼠标滚轮缩放 map.enableScrollWheelZoom(true) //去除对应水印 removeMaker('BMap_cpyCtrl') removeMaker('anchorBL') }) }) break; //如果需要添加别的地图引擎,请在这里书写case 语句 default: console.log('error') break; } }
百度开发者密钥申请:
http://lbsyun.baidu.com/index.php?title=jspopular/guide/getkey
Here地图手令申请:
https://openlocation.here.com/contact
不要小看这个函数,这里有好两个大坑。
1.document.getElementsByClassName这个获取的是一个Htmlconnection对象,而且是动态的,无法直接通过js对其操作
2.由于script和dom树同步执行,执行这段代码时,ele并未正确加载,此时无法对这个Htmlconnection对象操作,只能等待他正确的加载了dom树之后再去操作这个水印(我知道这段代码很野鸡,不过暂时没有想到好的方法去实现他,而且30ms也是人眼无法察觉的误差,我就默许了)
//通过类名修改隐藏元素 -> 变相去除水印
//className -> String 类名
function removeMaker(className) {
let ele = document.getElementsByClassName(className)
setTimeout(() => {
for (item of ele) {
item.parentNode.removeChild(item)
}
}, 30)
}
我在地图之间的切换过程中发现,百度地图的一些附加的东西在Here地图加载的时候并没有完全清除掉,索性一不做二不休,每次渲染之前把之前渲染的地图直接干掉(友情提示:此操作增加了dom操作,降低了性能,可以忽略)
//清空地图容器,避免重复渲染
function removeMapArea() {
let MapEngineContant = document.getElementById('MapEngineContant')
let childs = MapEngineContant.childNodes
for (let i = childs.length - 1; i >= 0; i--) {
MapEngineContant.removeChild(childs[i]);
}
}
在只有以上函数的情况下,demo也能正常跑起来,不过需要手动设置默认的地图类型。这个函数主要就是切换地图使用。
//地图切换函数
function MapChange() {
let MapSelected = document.getElementById('MapEngineList')
//获取当前选择项的值
let selectedMap = MapSelected.options[MapSelected.selectedIndex].value
//获取对应的地图引擎
for (Mapitem in MapEngineList) {
MapEngineList[Mapitem] === selectedMap ? LoadMap(Mapitem) : null
}
}
这个demo看着很简单,但是很符合一些对应的业务逻辑使用场景,而且,差不多的变量我都抽取出来了,在模块化开发中可以很快的和别的模块之间进行对接。由于只是功能的实现,并没有多少样式的调整,大家将就看一下,多多包涵。
/* * 地图引擎: * 需求:拿到 ->地图引擎名<-,去匹配对应的引擎,并加载初始化地图 * 返回 ->对应的地图引擎<- 提供给MapHelper.js用于初始化 * */ //默认地图引擎,由系统设置提供 //具体数据猜测应该放在redux仓库中 通过模块导入 const defaultMapEngine = 'BaiduMap' //可支持的地图引擎 const MapEngineList = { BaiduMap: '百度地图', HereMap: 'Here地图', TencentMap: '腾讯地图', GaodeMap: '高德地图', BinyingMap: '必应地图' } //起始坐标点,外部参数,(坐标定位暂时不处理,需要根据算法重新换算) const defaulePoint = { x: 0, y: 0 } //显示可选地图列表 RenderMapList(MapEngineList) //加载默认地图 LoadMap(defaultMapEngine) //绑定地图切换事件 document.getElementById('MapEngineList').onchange = MapChange //地图切换函数 function MapChange() { let MapSelected = document.getElementById('MapEngineList') //获取当前选择项的值 let selectedMap = MapSelected.options[MapSelected.selectedIndex].value //获取对应的地图引擎 for (Mapitem in MapEngineList) { MapEngineList[Mapitem] === selectedMap ? LoadMap(Mapitem) : null } } //根据 MapEngineList 来渲染页面的地图选择选项 //MapList -> Object 可支持的地图引擎 function RenderMapList(MapList) { //获取地图显示列表 let MapShowList = document.getElementById('MapEngineList') //渲染地图显示列表 for (Mapitem in MapList) { let MapListNode = document.createElement('option') let text = document.createTextNode(`${MapList[Mapitem]}`) MapListNode.appendChild(text); MapShowList.appendChild(MapListNode) //默认显示 默认加载项 if (`${Mapitem}` === defaultMapEngine) MapListNode.setAttribute('selected', 'selected') } } //根据参数加载对应地图(并去掉对应的水印) //MapEngine -> String 地图引擎 function LoadMap(MapEngine) { switch (MapEngine) { //Here地图 case 'HereMap': loadScript('http://js.api.here.com/v3/3.0/mapsjs-core.js', function () { loadScript('http://js.api.here.com/v3/3.0/mapsjs-service.js', function () { removeMapArea() console.log('Here地图加载OK'); let platform = new H.service.Platform({ 'app_id': '******************', 'app_code': '******************' }); let defaultLayers = platform.createDefaultLayers() new H.Map( MapEngineContant, defaultLayers.normal.map, { zoom: 14, center: { lat: 52.5, lng: 13.4 } }); //去除相关水印 let HereMaker = document.querySelector('#MapEngineContant>div:last-child>div:last-child') HereMaker.parentNode.removeChild(HereMaker) }) }) break; //百度地图 case 'BaiduMap': loadScript('http://api.map.baidu.com/api?v=2.0&ak=******************', function () { loadScript('http://api.map.baidu.com/getscript?v=2.0&ak=******************&services=&t=20190102133327', function () { removeMapArea() console.log('百度地图加载OK'); // 创建地图实例 let map = new BMap.Map('MapEngineContant') // 创建点坐标 let point = new BMap.Point(116.404, 39.915) // 初始化地图,设置中心点坐标和地图级别 map.centerAndZoom(point, 22) //开启鼠标滚轮缩放 map.enableScrollWheelZoom(true) //去除对应水印 removeMaker('BMap_cpyCtrl') removeMaker('anchorBL') }) }) break; default: console.log('error') break; } } //动态加载script //url -> String 资源加载地址 function loadScript(url, callback) { let script = document.createElement('script') script.type = 'text/javascript' if (script.readyState) { //IE浏览器 script.onreadystatechange = function () { if (script.readyState == 'loaded' || script.readyState == 'complete') { script.onreadystatechange = null; callback() } }; } else { //标准浏览器 script.onload = function () { callback() }; } script.src = url document.getElementsByTagName('head')[0].appendChild(script) } //通过类名修改隐藏元素 -> 变相去除水印 //className -> String 类名 function removeMaker(className) { let ele = document.getElementsByClassName(className) setTimeout(() => { for (item of ele) { item.parentNode.removeChild(item) } }, 50) } //清空地图容器,避免重复渲染 function removeMapArea() { let MapEngineContant = document.getElementById('MapEngineContant') let childs = MapEngineContant.childNodes for (let i = childs.length - 1; i >= 0; i--) { MapEngineContant.removeChild(childs[i]); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。