所有分类
  • 所有分类
  • Html5资源
  • React资源
  • Vue资源
  • Php资源
  • ‌小程序资源
  • Python资源

Vue3 + vue-baidu-map 百度地图开发宝典:定位、标记、区域绘制一站式解决方案

简介

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 开发者提供了强大的地图功能集成能力。通过本文档的介绍,您可以:

  1. 快速集成百度地图到 Vue3 项目
  2. 实现基础的地图显示和交互
  3. 添加标记点和信息窗口
  4. 绘制各种覆盖物(圆形、多边形等)
  5. 获取用户位置并进行定位
  6. 计算距离和判断区域范围
  7. 解决常见的开发问题

在实际项目中,建议根据具体需求选择合适的功能组合,并注意处理坐标系转换、错误处理和移动端适配等问题。

参考资源

资源下载
下载价格免费
注意:本网站资源属于虚拟产品,不支持退款。请谨慎购买! 购买后资源无法下载,请联系客服QQ:844475003,微信号:th844475003。
原文链接:https://code.ifrontend.net/archives/893,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?