
简介
vue-baidu-map 是一个基于百度地图 JavaScript API 的 Vue.js 组件库,为 Vue 开发者提供了便捷的地图集成解决方案。本文档将详细介绍如何在 Vue3 项目中使用 vue-baidu-map 实现各种地图功能。
安装配置
1. 安装依赖
npm install vue-baidu-map --save
2. 获取百度地图 AK
访问 百度地图开放平台,注册账号并创建应用获取 AK(Access Key)。
3. 全局注册(推荐)
在 main.js
中全局注册:
import { createApp } from "vue";
import App from "./App.vue";
import BaiduMap from "vue-baidu-map";
const app = createApp(App);
app.use(BaiduMap, {
ak: "YOUR_BAIDU_MAP_AK", // 替换为你的百度地图AK
});
app.mount("#app");
4. 按需引入
如果只需要特定组件,可以按需引入:
import { BaiduMap, BmNavigation, BmGeolocation, BmCircle } from "vue-baidu-map";
基础地图实现
基本地图组件
<template>
<div class="map-container">
<baidu-map
class="map"
:center="center"
:zoom="zoom"
:scroll-wheel-zoom="true"
@ready="handleMapReady"
>
<!-- 地图控件 -->
<bm-navigation anchor="BMAP_ANCHOR_TOP_RIGHT"></bm-navigation>
<bm-geolocation
anchor="BMAP_ANCHOR_BOTTOM_RIGHT"
:showAddressBar="true"
:autoLocation="true"
></bm-geolocation>
</baidu-map>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
// 地图中心点坐标
const center = reactive({
lng: 116.404,
lat: 39.915,
});
// 地图缩放级别
const zoom = ref(15);
// 地图准备就绪回调
const handleMapReady = ({ BMap, map }) => {
console.log("地图加载完成", BMap, map);
// 可以在这里进行地图的进一步配置
};
</script>
<style scoped>
.map-container {
width: 100%;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.map {
width: 100%;
height: 500px;
background-color: #f0f0f0;
}
/* 隐藏百度地图版权信息 */
:deep(.anchorBL) {
display: none !important;
}
</style>
地图标记与覆盖物
添加标记点
<template>
<div class="map-container">
<baidu-map
class="map"
:center="center"
:zoom="zoom"
@ready="handleMapReady"
>
<!-- 标记点 -->
<bm-marker
v-for="marker in markers"
:key="marker.id"
:position="marker.position"
:dragging="marker.dragging"
@click="handleMarkerClick(marker)"
>
<!-- 信息窗口 -->
<bm-info-window
:show="marker.showInfo"
@close="marker.showInfo = false"
>
<div>
<h4>{{ marker.title }}</h4>
<p>{{ marker.content }}</p>
</div>
</bm-info-window>
</bm-marker>
</baidu-map>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
const center = reactive({
lng: 116.404,
lat: 39.915,
});
const zoom = ref(15);
// 标记点数据
const markers = ref([
{
id: 1,
position: { lng: 116.404, lat: 39.915 },
title: "北京天安门",
content: "中华人民共和国的象征",
dragging: false,
showInfo: false,
},
{
id: 2,
position: { lng: 116.407, lat: 39.918 },
title: "故宫博物院",
content: "明清两朝的皇家宫殿",
dragging: false,
showInfo: false,
},
]);
// 标记点击事件
const handleMarkerClick = (marker) => {
marker.showInfo = true;
};
const handleMapReady = ({ BMap, map }) => {
console.log("地图加载完成");
};
</script>
绘制圆形区域
<template>
<div class="map-container">
<baidu-map class="map" :center="center" :zoom="zoom">
<!-- 圆形覆盖物 -->
<bm-circle
:center="circleCenter"
:radius="radius"
:stroke-color="strokeColor"
:stroke-weight="strokeWeight"
:stroke-opacity="strokeOpacity"
:fill-color="fillColor"
:fill-opacity="fillOpacity"
:editing="editing"
@lineupdate="handleCircleUpdate"
></bm-circle>
</baidu-map>
<!-- 控制面板 -->
<div class="control-panel">
<button @click="toggleEditing">
{{ editing ? "完成编辑" : "编辑圆形" }}
</button>
<div>半径: {{ radius }}米</div>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
const center = reactive({
lng: 116.404,
lat: 39.915,
});
const zoom = ref(15);
// 圆形配置
const circleCenter = reactive({
lng: 116.404,
lat: 39.915,
});
const radius = ref(500);
const strokeColor = ref("#FF0000");
const strokeWeight = ref(2);
const strokeOpacity = ref(0.8);
const fillColor = ref("#FF0000");
const fillOpacity = ref(0.2);
const editing = ref(false);
// 切换编辑模式
const toggleEditing = () => {
editing.value = !editing.value;
};
// 圆形更新事件
const handleCircleUpdate = (e) => {
circleCenter.lng = e.target.getCenter().lng;
circleCenter.lat = e.target.getCenter().lat;
radius.value = Math.round(e.target.getRadius());
};
</script>
<style scoped>
.map-container {
position: relative;
width: 100%;
height: 100vh;
}
.map {
width: 100%;
height: 100%;
}
.control-panel {
position: absolute;
top: 20px;
left: 20px;
background: white;
padding: 15px;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
z-index: 1000;
}
.control-panel button {
background: #007bff;
color: white;
border: none;
padding: 8px 16px;
border-radius: 4px;
cursor: pointer;
margin-bottom: 10px;
}
.control-panel button:hover {
background: #0056b3;
}
</style>
定位与导航功能
获取用户当前位置
<template>
<div class="map-container">
<baidu-map
class="map"
:center="center"
:zoom="zoom"
@ready="handleMapReady"
>
<!-- 当前位置标记 -->
<bm-marker
v-if="currentPosition.lng"
:position="currentPosition"
:icon="locationIcon"
>
<bm-info-window :show="showLocationInfo">
<div>
<h4>当前位置</h4>
<p>经度: {{ currentPosition.lng.toFixed(6) }}</p>
<p>纬度: {{ currentPosition.lat.toFixed(6) }}</p>
<p>地址: {{ currentAddress }}</p>
</div>
</bm-info-window>
</bm-marker>
</baidu-map>
<!-- 定位按钮 -->
<div class="location-controls">
<button @click="getCurrentLocation" :disabled="locating">
{{ locating ? "定位中..." : "获取当前位置" }}
</button>
</div>
</div>
</template>
<script setup>
import { ref, reactive } from "vue";
const center = reactive({
lng: 116.404,
lat: 39.915,
});
const zoom = ref(15);
const locating = ref(false);
const showLocationInfo = ref(false);
const currentAddress = ref("");
// 当前位置
const currentPosition = reactive({
lng: 0,
lat: 0,
});
// 自定义定位图标
const locationIcon = reactive({
url: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iMTAiIGZpbGw9IiMwMDdCRkYiLz4KPGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgcj0iNCIgZmlsbD0id2hpdGUiLz4KPC9zdmc+",
size: { width: 24, height: 24 },
});
// 获取当前位置
const getCurrentLocation = async () => {
locating.value = true;
try {
// 使用浏览器原生定位API
const position = await new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(resolve, reject, {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 60000,
});
});
// 转换坐标系(WGS84 转 GCJ02)
const coords = await convertCoordinates(
position.coords.longitude,
position.coords.latitude
);
currentPosition.lng = coords.lng;
currentPosition.lat = coords.lat;
// 更新地图中心
center.lng = coords.lng;
center.lat = coords.lat;
// 获取地址信息
await getAddressByCoords(coords.lng, coords.lat);
showLocationInfo.value = true;
} catch (error) {
console.error("定位失败:", error);
alert("定位失败,请检查定位权限设置");
} finally {
locating.value = false;
}
};
// 坐标转换(WGS84 转 GCJ02)
const convertCoordinates = async (lng, lat) => {
// 这里可以调用百度地图的坐标转换API
// 或者使用第三方坐标转换库
return { lng, lat }; // 简化处理,实际项目中需要进行坐标转换
};
// 根据坐标获取地址
const getAddressByCoords = async (lng, lat) => {
// 使用百度地图逆地理编码API
try {
const response = await fetch(
`https://api.map.baidu.com/reverse_geocoding/v3/?ak=YOUR_AK&output=json&coordtype=gcj02ll&location=${lat},${lng}`
);
const data = await response.json();
if (data.status === 0) {
currentAddress.value = data.result.formatted_address;
}
} catch (error) {
console.error("获取地址失败:", error);
currentAddress.value = "地址获取失败";
}
};
const handleMapReady = ({ BMap, map }) => {
console.log("地图加载完成");
};
</script>
<style scoped>
.map-container {
position: relative;
width: 100%;
height: 100vh;
}
.map {
width: 100%;
height: 100%;
}
.location-controls {
position: absolute;
bottom: 20px;
left: 20px;
z-index: 1000;
}
.location-controls button {
background: #28a745;
color: white;
border: none;
padding: 12px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 14px;
}
.location-controls button:hover:not(:disabled) {
background: #218838;
}
.location-controls button:disabled {
background: #6c757d;
cursor: not-allowed;
}
</style>
实用工具函数
距离计算
/**
* 计算两点之间的距离(米)
* @param {number} lat1 第一个点的纬度
* @param {number} lng1 第一个点的经度
* @param {number} lat2 第二个点的纬度
* @param {number} lng2 第二个点的经度
* @returns {number} 距离(米)
*/
export function calculateDistance(lat1, lng1, lat2, lng2) {
const radLat1 = (lat1 * Math.PI) / 180.0;
const radLat2 = (lat2 * Math.PI) / 180.0;
const a = radLat1 - radLat2;
const b = (lng1 * Math.PI) / 180.0 - (lng2 * Math.PI) / 180.0;
let s =
2 *
Math.asin(
Math.sqrt(
Math.pow(Math.sin(a / 2), 2) +
Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)
)
);
s = s * 6378.137; // 地球半径
s = Math.round(s * 1000); // 转换为米
return s;
}
/**
* 判断点是否在圆形区域内
* @param {Object} point 点坐标 {lng, lat}
* @param {Object} center 圆心坐标 {lng, lat}
* @param {number} radius 半径(米)
* @returns {boolean} 是否在区域内
*/
export function isPointInCircle(point, center, radius) {
const distance = calculateDistance(
point.lat,
point.lng,
center.lat,
center.lng
);
return distance <= radius;
}
常见问题与解决方案
1. 坐标系问题
国内地图必须使用 GCJ02 坐标系,GPS 获取的 WGS84 坐标需要转换:
// 使用百度地图坐标转换API
const convertCoordinates = async (
lng,
lat,
from = "wgs84ll",
to = "gcj02ll"
) => {
const response = await fetch(
`https://api.map.baidu.com/geoconv/v1/?coords=${lng},${lat}&from=${from}&to=${to}&ak=YOUR_AK`
);
const data = await response.json();
if (data.status === 0) {
return {
lng: data.result[0].x,
lat: data.result[0].y,
};
}
throw new Error("坐标转换失败");
};
2. 地图样式自定义
/* 隐藏百度地图控件 */
:deep(.anchorBL) {
display: none !important;
} /* 版权信息 */
:deep(.BMap_cpyCtrl) {
display: none !important;
} /* 版权控件 */
:deep(.anchorTR) {
display: none !important;
} /* 右上角控件 */
/* 自定义地图容器样式 */
.baidu-map {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
3. 移动端适配
<style scoped>
.map-container {
width: 100%;
height: 100vh;
}
.map {
width: 100%;
height: 100%;
}
/* 移动端适配 */
@media (max-width: 768px) {
.control-panel {
left: 10px;
right: 10px;
top: 10px;
padding: 10px;
}
.location-controls {
left: 10px;
right: 10px;
bottom: 10px;
}
.location-controls button {
width: 100%;
padding: 15px;
}
}
</style>
总结
vue-baidu-map 为 Vue 开发者提供了强大的地图功能集成能力。通过本文档的介绍,您可以:
- 快速集成百度地图到 Vue3 项目
- 实现基础的地图显示和交互
- 添加标记点和信息窗口
- 绘制各种覆盖物(圆形、多边形等)
- 获取用户位置并进行定位
- 计算距离和判断区域范围
- 解决常见的开发问题
在实际项目中,建议根据具体需求选择合适的功能组合,并注意处理坐标系转换、错误处理和移动端适配等问题。
参考资源
原文链接:https://code.ifrontend.net/archives/893,转载请注明出处。
评论0