搞了我两天的一个问题。
hbuilderx版本:4.36
问题介绍:
我的项目是公司的项目,需要在H5端使用百度地图,使用vue-cli创建的uniapp,就是uni代码在src里的目录结构。就是使用这种方式才会遇到这个问题。用法是直接在manifest.json配置bmap,然后使用内置组件map。百度地图用不了。
问题原因:
cli创建的项目编译时不是使用hbuilderx编译,而是使用自己的node_modules内的uni依赖包编译(如果你直接在hbuilderx新建项目你会发现没有node_modules,因为用的是hbuilderx的环境编译),所以导致版本跟不上。map组件找不到manifest.json配置的百度地图key。其他的key可以。
这里有个坑。腾讯地图的mapkey名不同hbuilderx版本属性名不一样,V4.36后(包括V4.36)是tencent,老的是qqmap。当我用hbuilderx配置勾选腾讯地图后在manifest.json内看到的key名是tencent,但我的项目是cli创建的老版本编译,只能识别qqmap,所以也会导致:Map key not configured csdn。
解决办法:
在public文件夹下的index.html加入
<script type="text/javascript" src="https://api.map.baidu.com/api?v=3.0&&type=webgl&ak=你的key"></script>
然后在页面使用
<template>
<view class="car-position-map">
<div id='baiduMapContainer' class="map"></div>
</view>
</template>
// js
var map = new BMapGL.Map("baiduMapContainer"); // 创建地图实例
var point = new BMapGL.Point(this.longitude, this.latitude); // 创建点坐标
map.centerAndZoom(point, 16); // 初始化地图,设置中心点坐标和地图级别
var marker = new BMapGL.Marker(point);
map.addOverlay(marker);
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
最方便的还是使用Uniapp内置的map组件,不过我试了下,在我的项目弄不了,应该是编译版本不支持,又不好改。
如果不是cli项目,可以配置百度地图key.需要在manifest.json源码自己添加,hbuilderx 定位和地图可视化配置不能勾百度地图,以后可能会更新。
"h5" : {
"sdkConfigs" : {
"maps" : {
"bmap" : {
// 百度地图秘钥(HBuilderX 3.99+)http://lbsyun.baidu.com/apiconsole/key#/home
"key" : ""
}
}
}
}
运行效果
自己写的一个模仿uniapp内置map的组件
<template>
<!-- 模拟uniapp map组件 -->
<div id='baiduMapContainer' class="map"></div>
</template>
<script>
import { coordinateShift, coordinateShiftGCJ } from "@/utils/common"
export default {
name: 'baiduMap',
props: {
id: {
type: String,
default: ''
},
latitude: {
type: [String, Number],
default: 39.92
},
longitude: {
type: [String, Number],
default: 116.46
},
scale: {
type: [String, Number],
default: 16
},
markers: {
type: Array,
default () {
return []
}
},
covers: {
type: Array,
default () {
return []
}
},
// includePoints: {
// type: Array,
// default () {
// return []
// }
// },
polyline: {
type: Array,
default () {
return []
}
},
circles: {
type: Array,
default () {
return []
}
},
controls: {
type: Array,
default () {
return []
}
},
showLocation: {
type: [Boolean, String],
default: false
},
enableTraffic: {
type: [Boolean, String],
default: false
},
libraries: {
type: Array,
default () {
return []
}
},
polygons: {
type: Array,
default: () => []
}
},
data() {
return {
markerZIndex: 700,
circle: null, // 圆实例
// mapScale: 16,
map: null,
polyLineHandleObj: [], // 保存点折线实例
markerHandleObj: [], // 根据传入的markers id存入操作对象和信息,便于操作点标签
tempIcon: "https://img0.baidu.com/it/u=1848373536,836779508&fm=253&app=120&size=w931&n=0&f=JPEG&fmt=auto?sec=1734109200&t=f268c95df20d59d0cf92c89e1a29dfce",
};
},
watch: {
enableTraffic(enable) {
if (enable) {
this.map.setTrafficOn();
} else {
this.map.setTrafficOff();
}
},
polyline: {
deep: true,
immediate: true,
async handler(val) {
if (val && val.length) {
this.removeOverlay(this.polyLineHandleObj) // 重置
// console.log("更新线:", val)
this.polyline.forEach(item => {
if (item.points && item.points.length !== 0) {
this.addPolyline(item)
}
})
}
},
},
markers: {
deep: true,
async handler(val) {
if (val && val.length) {
// this.markerHandleObj = [] // 清空旧的
// console.log("更新地图点标记:", this.markers)
this.markers.forEach((markerItem, index) => {
this.addMarker(markerItem)
})
}
},
},
circles: {
deep: true,
immediate: true,
async handler(val) {
if (val && val.length !== 0) {
// console.log("更新圆:", this.circles)
if (!this.map) setTimeout(() => {
this.circles.forEach((item, index) => {
this.addCircle({
longitude: this.longitude,
latitude: this.latitude,
option: item
})
})
}, 50)
else {
this.circles.forEach((item, index) => {
this.addCircle({
longitude: this.longitude,
latitude: this.latitude,
option: item
})
})
}
}
},
},
longitude() {
this.moveToLocation({longitude: this.longitude, latitude: this.latitude})
},
latitude() {
this.moveToLocation({longitude: this.longitude, latitude: this.latitude})
},
},
mounted() {
this.initMap();
},
methods: {
coordinateShift, coordinateShiftGCJ,
// 定义一个函数来计算两点之间的方向角(以度为单位),并返回0-360度的旋转角度
calculateRotationAngle(lat1, lon1, lat2, lon2) {
// 将经纬度差转换为角度差(这里我们简化计算,没有考虑地球的曲率)
const dLat = (lat2 - lat1) * (180 / Math.PI); // 纬度差转换为度
const dLon = (lon2 - lon1) * (180 / Math.PI) * Math.cos((lat1 + lat2) / 2 * (Math.PI / 180)); // 经度差转换为度,并考虑了两点纬度的平均值来计算cos值(这是一个更精确的经度差计算方法,但仍然基于平面几何的假设)
// 计算方向角(相对于正北方向,顺时针为正)
let angle = Math.atan2(dLon, dLat) * (180 / Math.PI); // atan2返回的是-180到180度的值
// 将方向角转换为0-360度的旋转角度
if (angle < 0) {
angle += 360;
}
return angle;
},
// 让一个已存在地图中的标记按路线移动
moveAlong(option) {
// option.duration=500
// option.path=option.path.slice(0,20)
const {markerId, autoRotate, duration} = option
let path = option.path.map((item, i) => {
let azimuth = null
if (i !== option.path.length - 1) {
const current = item;
const next = option.path[i + 1];
azimuth = this.calculateRotationAngle(current.latitude, current.longitude, next.latitude, next.longitude);
}
const coordinate = this.coordinateShift(item.longitude, item.latitude)
return {
lat: coordinate.latitude,
lng: coordinate.longitude,
rotation: azimuth
}
})
// console.log('移动', option, path)
var steps = path.length - 1; // 路径的步数(这里假设路径是由多个点组成的线段)
var stepTime = duration / steps; // 每步的时间(毫秒)
var currentIndex = 0; // 当前位置的索引
var timer = setInterval(() => {
try {
if (currentIndex < steps) {
var handleObj = this.markerHandleObj.find(item => item.markerInfo.id === markerId);
var currentPoint = path[currentIndex]; // 获取当前位置的坐标点
var nextPoint = path[currentIndex + 1]; // 获取下一个位置的坐标点(用于计算方向等,这里未使用)
// 刚开始时可能要移动的标记还没加到地图上
if (handleObj) {
handleObj.marker.setPosition(nextPoint); // 更新当前位置的标记点
handleObj.marker.setRotation(currentPoint.rotation || 0); // 更新当前位置的标记点
}
currentIndex++; // 更新当前位置的索引
} else {
if (option.success) {
option.success()
}
clearInterval(timer); // 移动完成后清除定时器
}
} catch(err) {
console.log(err)
clearInterval(timer);
}
}, stepTime); // 定时器的时间间隔(毫秒)
},
// // GCJ-02坐标转换成百度的BD09坐标
// coordinateShift(lng, lat) {
// let x_pi = (3.14159265358979324 * 3000.0) / 180.0;
// let x = lng;
// let y = lat;
// let z = Math.sqrt(x * x + y * y) + 0.00002 * Math.sin(y * x_pi);
// let theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * x_pi);
// let lngs = z * Math.cos(theta) + 0.0065;
// let lats = z * Math.sin(theta) + 0.006;
// return {
// longitude: lngs,
// latitude: lats
// };
// },
// // 百度的BD09坐标转换成GCJ-02坐标
// coordinateShiftGCJ(lng, lat) {
// let x_pi = (3.14159265358979324 * 3000.0) / 180.0;
// let x = lng - 0.0065;
// let y = lat - 0.006;
// let z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_pi);
// let theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_pi);
// let lngs = z * Math.cos(theta);
// let lats = z * Math.sin(theta);
// return {
// longitude: lngs,
// latitude: lats
// };
// },
// 删除一组overlay
removeOverlay(arr) {
arr.forEach(item => {
this.map.removeOverlay(item);
})
},
// 添加一条线
addPolyline(line) {
if (line.points && line.points.length !== 0) {
const points = line.points.map(item => {
const coordinate = this.coordinateShift(item.longitude, item.latitude)
return {
lat: coordinate.latitude,
lng: coordinate.longitude,
}
})
const polyline = new BMapGL.Polyline(points, {
strokeColor: line.color,
strokeWeight: 8
})
this.$nextTick(() => {
this.map.addOverlay(polyline);
// 简单做法,没辨别id,暂时没这个需求
this.polyLineHandleObj.push(polyline)
})
}
},
// 添加单个标记
addMarker(markerItem) {
this.$nextTick(() => {
let handleObj = null;
handleObj = this.markerHandleObj.find(item => {
return item.markerInfo.id === markerItem.id
})
if (!handleObj) {
this.markerHandleObj.push({
markerInfo: null,
marker: null
})
handleObj = this.markerHandleObj[this.markerHandleObj.length - 1]
}
if (handleObj) {
// 信息没变则不更新标记
if (JSON.stringify(markerItem) !== handleObj.markerInfo) {
handleObj.markerInfo = JSON.parse(JSON.stringify(markerItem));
const shiftP = this.coordinateShift(markerItem.longitude, markerItem.latitude)
var point = new BMapGL.Point(shiftP.longitude, shiftP.latitude); // 创建点坐标
// 初始化标记实例
if (!handleObj.marker) {
// 创建点标记图标
var markerIcon = new BMapGL.Icon(markerItem.iconPath, new BMapGL.Size(markerItem.width,
markerItem.height));
let marker = null;
if (markerItem.customCallout && markerItem.address) {
// 创建标签
//
marker = new BMapGL.Label(
`<img src='${markerItem.iconPath}' style='vertical-align:middle; width: 16px; height: 16px;'/>` +
markerItem.address, {
point,
// offset:{}
});
// 设置label的样式
marker.setStyle(markerItem.styles);
marker.id = markerItem.id
marker.setZIndex(999);
// 为label添加点击事件监听器
marker.addEventListener("click", (e) => {
this.$emit('callouttap', e)
// 在这里执行你所需的操作
});
// marker = new BMapGL.Marker(point, {
// icon: markerIcon
// });
} else {
marker = new BMapGL.Marker(point, {
icon: markerIcon
});
if (this.markerZIndex >= 500) {
setTimeout(() => {
//降低marker父节点层级,防止label被覆盖点击不到。这会导致点击不到marker
let son = document.getElementsByClassName('BMap_Marker')[0]
this.markerZIndex = 499;
if (son) {
son.parentNode.style.zIndex = this.markerZIndex
}
}, 1000)
}
}
handleObj.marker = marker;
handleObj.markerInfo = markerItem
this.map.addOverlay(handleObj.marker);
handleObj.marker.setPosition(point); // 立即更新位置,修复某些时候第一次没渲染出来的bug
console.log('添加标记', markerItem)
// alert(markerItem.longitude)
// alert(shiftP.longitude)
} else {
// 更新点标记的坐标
handleObj.marker.setPosition(point);
}
// 更新车的旋转角度
if (markerItem.rotate) {
handleObj.marker.setRotation(markerItem.rotate);
}
}
}
})
},
// 添加一组标记
addMarkers(info) {
if (info.clear) {
this.removeOverlay(this.markerHandleObj.map(item => item.marker))
this.markerHandleObj = [] // 清空旧的
}
info.markers.forEach(item => {
this.addMarker(item)
})
// console.log('addMarkers', info)
},
initMap() {
var map = new BMapGL.Map("baiduMapContainer"); // 创建地图实例
const shiftP = this.coordinateShift(this.longitude, this.latitude)
var point = new BMapGL.Point(shiftP.longitude, shiftP.latitude); // 创建点坐标
map.centerAndZoom(point, this.scale); // 初始化地图,设置中心点坐标和地图级别
map.enableScrollWheelZoom(true); //开启鼠标滚轮缩放
map.addEventListener('click', (e) => {
const shiftP = this.coordinateShiftGCJ(e.latlng.lng, e.latlng.lat)
e.detail = {
latitude: shiftP.latitude,
longitude: shiftP.longitude
}
this.$emit('onMapClick', e, map)
});
this.map = map;
console.log('初始化地图', this.longitude, this.latitude)
// 创建一个定位对象
var geolocation = new BMapGL.Geolocation();
// 启用SDK辅助定位
geolocation.enableSDKLocation();
// // 开始定位
// geolocation.getCurrentPosition(function(r){
// console.log(111, r)
// },{enableHighAccuracy: true})
// navigator.geolocation.getCurrentPosition(
// function(position) {
// // 处理地理位置信息
// var latitude = position.coords.latitude;
// var longitude = position.coords.longitude;
// console.log("Latitude: " + latitude + ", Longitude: " + longitude);
// },
// function(error) {
// // 处理错误
// console.error("Error getting location: " + error.message);
// }
// );
},
// 画圆
async addCircle(info) {
if (info) {
// 删除旧的实例,暂时只支持画一个圆
if (this.map.getOverlays().length > 0) {
this.map.removeOverlay(this.circle); // 先移除旧的圆形
}
const shiftP = this.coordinateShift(info.longitude, info.latitude)
var point = new BMapGL.Point(shiftP.longitude, shiftP.latitude); // 创建点坐标
this.circle = new BMapGL.Circle(point, info.option.radius, info.option);
// this.circle.setCenter(new LatLng(39.916935, 116.372119));
this.map?.addOverlay(this.circle);
}
},
moveToLocation(location) {
const shiftP = this.coordinateShift(location.longitude, location.latitude)
var point = new BMapGL.Point(shiftP.longitude, shiftP.latitude);
//切换地图位置
this.map.centerAndZoom(point, this.scale);
if (location.success) location.success()
},
//info => {points: markers,padding: [60, 60, 60, 60],}
// 将视角拉伸到显示一组点
includePoints(info) {
if (info.points.length > 1) {
const points = []
info.points.forEach(item => {
const shiftP = this.coordinateShift(item.longitude, item.latitude)
points.push(new BMapGL.Point(shiftP.longitude, shiftP.latitude))
})
// 根据点坐标数组计算视图范围
var viewport = this.map.getViewport(points);
// 调整地图的中心点和缩放级别
this.map.centerAndZoom(viewport.center, viewport.zoom);
}
}
}
}
</script>
<style>
</style>
我试图看能不能升级cli依赖,然后直接使用uni内置map组件。
我看到我4.36使用的依赖版本是3.0.0-alpha-4030320241109002,在hbuilderx安装目录的plugins\uniapp-cli-vite\package.json可查看版本,是使用vite vue3版本的,不过我的项目是vue2普通版本,gg,不知道怎么升级。
export function getMapInfo () {
if (__uniConfig.qqMapKey) {
return {
type: MapType.QQ,
key: __uniConfig.qqMapKey
}
}
if (__uniConfig.googleMapKey) {
return {
type: MapType.GOOGLE,
key: __uniConfig.googleMapKey
}
}
if (__uniConfig.aMapKey) {
return {
type: MapType.AMAP,
key: __uniConfig.aMapKey,
securityJsCode: __uniConfig.aMapSecurityJsCode,
serviceHost: __uniConfig.aMapServiceHost
}
}
return {
type: MapType.UNKNOWN,
key: ''
}
}