vue3中封装基础高德地图组件

29 阅读1分钟
  1. 安装依赖

pnpm install @amap/amap-jsapi-loader --save

  1. 实现组件 ReAMap, 由useAMap.tsindex.vue构成

代码如下

useAMap.ts

import { shallowRef } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";

export function useAMap() {
  const map = shallowRef(null);

  const initMap = async (container: string | HTMLElement, options?: object) => {
    try {
      const AMap = await AMapLoader.load({
        key: "xxxx", // 生产环境建议将 Key 存储在配置文件中
        version: "2.0",
        plugins: []
      });
      map.value = new AMap.Map(container, {
        zoom: 11,
        center: [116.39, 39.9],
        ...options
      });
    } catch (error) {
      console.error("地图加载失败:", error);
    }
  };

  const destroyMap = () => {
    if (map.value) {
      map.value.destroy();
      map.value = null;
    }
  };

  return { map, initMap, destroyMap };
}

index.vue


<template>
  <div ref="mapContainer" class="re-amap-container" />
</template>

<script setup lang="ts">
import {
  ref,
  onMounted,
  onUnmounted,
  defineProps,
  withDefaults,
  defineExpose,
  watch
} from "vue";
import { useAMap } from "./useAMap";

// 定义 emits
const emit = defineEmits(["map-click"]);

// 定义 props
interface Props {
  options?: object;
  markerOptions?: object;
  infoWindow?: object;
}
const props = withDefaults(defineProps<Props>(), {
  options: () => ({}),
  markerOptions: null,
  infoWindow: null
});

const mapContainer = ref<HTMLElement | null>(null);
const { map, initMap, destroyMap } = useAMap();

// 监听地图实例创建
watch(map, newMap => {
  if (newMap) {
    // 绑定地图点击事件
    newMap.on("click", (e: any) => {
      emit("map-click", e.lnglat);
    });

    // 处理标记点和信息窗
    if (props.markerOptions) {
      const AMap = (window as any).AMap;
      const marker = new AMap.Marker(props.markerOptions);
      newMap.add(marker);

      if (props.infoWindow) {
        const infoWindow = new AMap.InfoWindow(props.infoWindow);
        marker.on("click", () => {
          infoWindow.open(newMap, marker.getPosition());
        });
      }
    }
  }
});

onMounted(() => {
  if (mapContainer.value) {
    initMap(mapContainer.value, props.options);
  }
});

onUnmounted(() => {
  destroyMap();
});

// 将 map 实例暴露给父组件
defineExpose({
  map
});
</script>

<style scoped>
.re-amap-container {
  width: 100%;
  height: 100%;
}
</style>

  1. 使用组件

省略了一部分代码,只贴主要的关键代码,对地图组件有什么操作,通过ref去控制即可

<script lang="ts" setup>
import { ref } from "vue";

const amapRef = ref(null);

const mapOptions = {
  center: [116.39, 39.9],
  zoom: 16
};

const markerOptions = {
  position: [116.39, 39.9],
  title: "xxx"
};

const infoWindowOptions = {
  isCustom: false, // 使用高德默认样式
  autoMove: true, // 点击标记点后自动平移地图,使信息窗完整显示
  offset: [11, -60], // 设置信息窗的偏移量
  content:
    '<div style="color: #333; font-size: 14px; padding: 10px;">地址:xxxx</div>'
};

const handleMapClick = lnglat => {
  console.log("地图点击位置:", lnglat);
};

</script>

<template>
    <div class="h-[173px] w-[526px]">
        <ReAMap
          ref="amapRef"
          :options="mapOptions"
          :marker-options="markerOptions"
          :info-window="infoWindowOptions"
          @map-click="handleMapClick"
        />
      </div>
</template>

实现效果可参考下图

image.png