记录踩坑 uniapp 引入百度地图(微信小程序,H5,APP)
前言
因为公司要求一定要用百度地图,网上引入百度地图的方法说的就三种(插件,异步,webview组件)
,因为我用的是VUE3
- 第一种方法引入插件(插件名vue-baidu-map)一直报错vue2没试过反正vue3引进去就是报错
- 第二种方法用异步引入 如果只开发app和h5可以用,微信小程序反正不显示,但是不知道为啥有时候不稳第一次引的时候(三端都显示除了微信小程序)是显示的第二次就不显示了h5没问题app端已初始化就一直报警告地图出不来;
- 第三种方法就是用webView组件嵌套html页面的方式把地图弄出来(我用的就是这种方式)
微信小程序引入百度地图的话就是你把H5写好在通过webView组件直接引进去 因为研究了两三天实在没有解决的办法着是我想到最好的解决办法了
1.异步引入
通过这种方式引入的好处就是你能在这里直接写一些逻辑不需要做交互(只做h5合适但是写h5的话也没必要用uniapp一堆坑建议直接用vue写h5)
第一步 \util\BaiDuMap.js
export function mymap(ak) {
return new Promise(function(resolve, reject) {
window.init = function() {
resolve(mymap)
}
var script = document.createElement('script')
script.type = 'text/javascript'
script.src = `http://api.map.baidu.com/api?v=3.0&ak=${ak}&callback=init`
script.onerror = reject
document.head.appendChild(script)
})
}
这里有个坑 你引v3.0的时候就不要加&type=webgl,加了就会变成GL版本是v1.0的 我也不知道为什么
第二步 回到你vue页面 建一个renderjs 的script
<template>
<!-- <view class="map" id="map"> </view> -->
</template>
// 重点 !!! 一定要是lang="renderjs" 必须给module命名 不然会报错 因为在renderjs可以操作dom
<script lang="renderjs" module="map">
import { mymap } from '../../util/BaiDuMap'
let BMap =null
export default{
data(){
return{
ak:"你自己的ak"
}
},
mounted(){
mymap(this.ak).then(mymap=>{
// v1.0的就是 BMapGL v3.0的就是BMap
BMap=BMap;
const map= new BMap.Map('map');
const point =new BMap.Point(116.404,39.04);
map.centerAndZoom(point,15)
var marker = new BMap.Marker(point); // 创建标注
map.addOverlay(marker);
})
}
}
</script>
2.webView嵌套方式
这种方法就比较麻烦了,需要你自己在html页面写一些逻辑还要和uniapp进行交互,如果只开发app端的话就不会很麻烦要开发小程序的话就必须要把h5写了然后开一个项目用webview
套h5的页面;
这种方式随便你用纯html 还是vue脚手架还是uniapp搭建h5的页面 我自己用的是cdn方式引入的vue3(图方便),如果要本地引的话最好目录:
记得下uni.webview.js的文件
第一步 在html引入下好的uni.webview.js和百度map的js
<script type="text/javascript" src="./js/uni.webview.js"></script>
<scripttype="text/javascript" src="http://api.map.baidu.com/apiv=3.0&ak=你自己的ak">
第二步 调地图
// html页面就一个<div class="map" id="map"></div>
<script>
document.addEventListener('UniAppJSBridgeReady', () => {
// 如果是脚手架ts的话这里会报错解决方式 (new (windows as any).BMap.Map('map')) 同理你用uni报错的话也面前面加(windows as any)
let map = new BMap.Map('map');
const point = new BMap.Point(120.2, 30.3);
map.centerAndZoom(point, 15)
let marker = new BMap.Marker(point) // 创建标注
map.addOverlay(marker)
map.enableScrollWheelZoom(true)
const location = new BMap.GeolocationControl({
anchor: BMAP_ANCHOR_BOTTOM_RIGHT // 这里用脚手架ts也会报错直接加(windows as any)
})
map.addControl(location) // 添加定位
})
</script>
写好这里你就可以去uniapp 引入webview组件src上面写你的线上地址或者本地地址
<web-view src="/static/map/map.html" @message="onMessage"></web-view>
第三步 通讯方式
app端:在html页面提前写好方法通过evalJs
就可以给webview发信息,webview给uniapp通过uni.postMessage({data:{// 你要传的参数 不知道能不能传方法过去调用没试过}})
// webView 给 uniapp 页面发信息
uni.postMessage({
data:{
// 你要传的参数 不知道能不能传方法过去调用没试过
}
})
// 然后uniapp页面@message="onMessage"的方法接收
const onMessage = (e) =>{
console.log(e.detail.data[0].state); // 接收到的数据
}
// uniapp 页面给webview页面发信息 html页面提前写好方法 然后evalJS('方法名(你要传的参数)') // 直接以字符串的形式写进去就可以了 所以这里用JSON.stringify
const {proxy} = getCurrentInstance();
proxy.$scope.$getAppWebview().children()[0].evalJS(`getAdminInfo(${JSON.stringify(point)})`);
h5端:html页面提前定义方法windows.top.方法名
,然后在uniapp页面通过windows.top.方法名
给webview发页面发信息,webview给h5发信息通过window.top?.postMessage({state}, '*') // 星号是代表全部 到了线上最好写你线上的域名
// webview页面 给 uniapp(h5)页面发送消息 记得加top!
window.top.postMessage({
// 你要传的参数
}, '*')// 星号是代表全部 到了线上最好写你线上的域名
// webview页面通过监听message来接收数据
window.top.addEventListener("message",function(e){
console.log(e.data.state)
},false)
// uniapp(h5)页面 webview页面通讯 同样也是用 windows.top.方法名 在html页面中提前写好方法就可以在
uniapp中调用了!!!
!!!切记这里有个坑
document.addEventListener('UniAppJSBridgeReady', () => {
// 把方法写在这里面 这样子在uniapp页面不会掉不到方法
windows.top.abc=function(e){
console.log(e) // 接收到信息
]
})
// uniapp页面调用
onMounted(()=>{
// 如果这样子没打印出来的话你就在这加个定时器 这个方法肯定是有的 测试了好多遍!!!!!!!!!
windows.top.abc("123");
})
PS:
如果你和我一样要多端开发小程序及app, 因为开发小程序不管用哪种方法都会有点bug不是显示不出来就是webview的层级太高了别的组件盖不不过去,别死磕了我磕了两三天真的没办法只想到了写好h5在套一层壳。
在写html页面的时候写方法建议这样写
window.top.abc=window.abc=function(){}
这样不管你在uniapp h5调用方法还是app中调用方法都调的到。