Vue3 高德地图

效果图:

一 、注册/登录获取key

https://lbs.amap.com/

使用手机号 / 邮箱注册开发者账号,完成实名认证(个人可身份证 / 企业可执照)。

html 复制代码
<template>
  <div style="height: 50px; display: flex; align-items: center">
    <div style="width: 200px; display: flex; justify-content: center">
      <el-select v-model="option.mapOptions.lang" placeholder="请选择语言">
        <el-option
          v-for="item in langOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        </el-option>
      </el-select>
    </div>
    <div style="width: 200px; display: flex; justify-content: center">
      <el-select
        v-model="option.mapOptions.amapStyleKey"
        placeholder="请选择主题"
      >
        <el-option
          v-for="item in themeOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        </el-option>
      </el-select>
    </div>
    <div style="width: 200px; display: flex; justify-content: center">
      <el-radio-group v-model="option.mapOptions.viewMode">
        <el-radio
          v-for="item in viewModeOptions"
          :key="item.value"
          :label="item.value"
          >{{ item.label }}</el-radio
        >
      </el-radio-group>
    </div>
    <div style="width: 200px; display: flex; justify-content: center">
      <el-select
        v-model="option.mapOptions.mapMarkerType"
        placeholder="请选择标记样式"
      >
        <el-option
          v-for="item in MarkerOptions"
          :key="item.value"
          :label="item.label"
          :value="item.value"
        >
        </el-option>
      </el-select>
    </div>
  </div>
  <div ref="vChartRef" style="width: 100%; height: calc(100vh - 50px)"></div>
</template>

<script setup lang="ts">
import { ref, toRefs, onMounted, watch } from "vue";
import AMapLoader from "@amap/amap-jsapi-loader";
import {
  FeaturesEnum,
  LangEnum,
  MarkerEnum,
  ThemeEnum,
  ViewModeEnum,
} from "./chartEnum";
import { reactive } from "vue";
import { isArray } from "lodash";

/***********************  地图切换 ***********************/
const themeOptions = [
  {
    value: ThemeEnum.NORMAL,
    label: "标准",
  },
  {
    value: ThemeEnum.DARK,
    label: "幻影黑",
  },
  {
    value: ThemeEnum.LIGHT,
    label: "月光银",
  },
  {
    value: ThemeEnum.WHITES_MOKE,
    label: "远山黛",
  },
  {
    value: ThemeEnum.FRESH,
    label: "草色青",
  },
  {
    value: ThemeEnum.GREY,
    label: "雅士灰",
  },
  {
    value: ThemeEnum.GRAFFITI,
    label: "涂鸦",
  },
  {
    value: ThemeEnum.MACARON,
    label: "马卡龙",
  },
  {
    value: ThemeEnum.BLUE,
    label: "靛青蓝",
  },
  {
    value: ThemeEnum.DARKBLUE,
    label: "极夜蓝",
  },
  {
    value: ThemeEnum.WINE,
    label: "酱籽",
  },
  {
    value: ThemeEnum.WEIXIN,
    label: "卫星",
  },
];

const langOptions = [
  {
    value: LangEnum.ZH_CN,
    label: "中文简体",
  },
  {
    value: LangEnum.EN,
    label: "英文",
  },
  {
    value: LangEnum.ZH_EN,
    label: "中英文对照",
  },
];

const viewModeOptions = [
  {
    value: ViewModeEnum.PLANE,
    label: "2D",
  },
  {
    value: ViewModeEnum.STEREOSCOPIC,
    label: "3D",
  },
];

const featuresOptions = [
  {
    value: FeaturesEnum.BG,
    label: "显示地图背景",
  },
  {
    value: FeaturesEnum.POINT,
    label: "显示标识",
  },
  {
    value: FeaturesEnum.ROAD,
    label: "显示道路",
  },
  {
    value: FeaturesEnum.BUILDING,
    label: "显示建筑",
  },
];

const MarkerOptions = [
  {
    value: MarkerEnum.CIRCLE_MARKER,
    label: "圆形标点",
  },
  {
    value: MarkerEnum.MARKER,
    label: "定位标点",
  },
  {
    value: MarkerEnum.NONE,
    label: "隐藏标点",
  },
];

/*********************** 地图 ***********************/

const chartData = ref([
  {
    name: "某某地市",
    value: 10,
    position: [116.300467, 39.907761],
  },
  {
    name: "某某地市",
    value: 15,
    position: [116.400567, 39.908761],
  },
  {
    name: "某某地市",
    value: 20,
    position: [116.200467, 39.937761],
  },
]);

const option = reactive({
  mapOptions: {
    pitch: 60, ///俯仰角度
    skyColor: "#53A9DE", //天空颜色
    amapKey: "AAAAASSDDDFFFFFFFFFFSDDDSDSADSDFSDFDDSD", //使用自己的高德应用key
    amapStyleKey: ThemeEnum.DARK, //地图主题
    amapStyleKeyCustom: "", //自定义地图样式
    amapLon: 116.397428, //地图中心经度
    amapLat: 39.90923, //地图中心纬度
    amapZindex: 11, //初始缩放
    marker: {
      fillColor: "#E98984FF", //填充颜色
      fillOpacity: 0.5, //透明度
      strokeColor: "white", //边框颜色
      strokeWeight: 2, //边框宽度
      strokeOpacity: 0.5, //边框透明度
      zIndex: 10, //层级
      bubble: true, //鼠标悬停时是否显示信息窗体
      cursor: "pointer", //鼠标悬停样式
      clickable: true, //是否可点击
    },
    mapMarkerType: MarkerEnum.CIRCLE_MARKER, //标点类型
    viewMode: ViewModeEnum.PLANE, // 2D/3D
    lang: LangEnum.ZH_CN, //语言
    features: [
      FeaturesEnum.BG, //显示地图背景
      FeaturesEnum.POINT, //显示标识
      FeaturesEnum.ROAD, //显示道路
      FeaturesEnum.BUILDING, //显示建筑
    ],
  },
});
let {
  amapKey,
  amapStyleKey,
  amapLon,
  amapLat,
  amapZindex,
  mapMarkerType,
  lang,
  amapStyleKeyCustom,
  features,
  viewMode,
  pitch,
  skyColor,
  marker,
} = toRefs(option.mapOptions);

let mapIns: any = null;
let markers: any = [];
let AMapIns: any = null;
const vChartRef = ref<HTMLElement>();

const dataHandle = (newData: any) => {
  if (!mapIns && !AMapIns) {
    initMap(option);
    return;
  }
  if (isArray(newData)) {
    // 先清除旧标记
    mapIns.remove(markers);
    markers = [];
    // 记录新标记
    if (mapMarkerType.value === MarkerEnum.MARKER) {
      newData.forEach((markerItem: any) => {
        const markerInstance = new AMapIns.Marker({
          position: [markerItem.position[0], markerItem.position[1]],
          offset: new AMapIns.Pixel(-13, -30),
        });
        markers.push(markerInstance);
        markerInstance.setMap(mapIns);
      });
    } else if (mapMarkerType.value === MarkerEnum.CIRCLE_MARKER) {
      newData.forEach((markerItem: any) => {
        const markerInstance = new AMapIns.CircleMarker({
          center: [markerItem.position[0], markerItem.position[1]],
          radius: markerItem.value,
          ...marker.value,
        });
        markers.push(markerInstance);
        markerInstance.setMap(mapIns);
      });
    }
  }
};

const initMap = (newData: any) => {
  // 初始化
  AMapLoader.load({
    key: amapKey.value, //api服务key--另外需要在public中使用安全密钥!!!
    version: "1.4.8", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
    plugins: ["AMap.PlaceSearch", "AMap.AutoComplete"], // 需要使用的的插件列表
  }).then((AMap: any) => {
    AMapIns = AMap;
    mapIns = new AMap.Map(vChartRef.value, {
      resizeEnable: true,
      zoom: amapZindex.value, // 地图显示的缩放级别
      center: [amapLon.value, amapLat.value],
      lang: lang.value,
      features: features.value,
      pitch: pitch.value, // 地图俯仰角度,有效范围 0 度- 83 度
      skyColor: skyColor.value,
      viewMode: viewMode.value, // 地图模式
      willReadFrequently: true,
    });
    dataHandle(chartData.value);
    let satellite = new AMap.TileLayer.Satellite();
    let roadNet = new AMap.TileLayer.RoadNet();
    if (newData.amapStyleKey === ThemeEnum.WEIXIN) {
      mapIns.add([satellite, roadNet]);
    } else {
      mapIns.remove([satellite, roadNet]);
      mapIns.setMapStyle(
        `amap://styles/${
          amapStyleKeyCustom.value !== ""
            ? amapStyleKeyCustom.value
            : amapStyleKey.value
        }`
      );
    }
  });
};

// 监听语言变化
watch(lang, (newLang) => {
  if (mapIns) {
    mapIns.setLang(newLang);
  }
});

// 监听主题变化
watch(amapStyleKey, (newStyle) => {
  if (mapIns && AMapIns) {
    let satellite = new AMapIns.TileLayer.Satellite();
    let roadNet = new AMapIns.TileLayer.RoadNet();
    if (newStyle === ThemeEnum.WEIXIN) {
      mapIns.add([satellite, roadNet]);
    } else {
      mapIns.remove([satellite, roadNet]);
      mapIns.setMapStyle(
        `amap://styles/${
          amapStyleKeyCustom.value !== "" ? amapStyleKeyCustom.value : newStyle
        }`
      );
    }
  }
});

// 监听视角模式变化
watch(viewMode, (newViewMode) => {
  if (mapIns && AMapIns) {
    try {
      // 先设置俯仰角度
      if (newViewMode === ViewModeEnum.STEREOSCOPIC) {
        mapIns.setPitch(pitch.value);
      } else {
        mapIns.setPitch(0);
      }

      // 重新初始化地图以确保viewMode正确应用
      const currentCenter = mapIns.getCenter();
      const currentZoom = mapIns.getZoom();
      const currentLang = lang.value;
      const currentFeatures = features.value;
      const currentSkyColor = skyColor.value;
      const currentStyleKey = amapStyleKey.value;
      const currentStyleKeyCustom = amapStyleKeyCustom.value;

      // 销毁并重新创建地图
      mapIns.destroy();

      mapIns = new AMapIns.Map(vChartRef.value, {
        resizeEnable: true,
        zoom: currentZoom,
        center: [currentCenter.lng, currentCenter.lat],
        lang: currentLang,
        features: currentFeatures,
        pitch: newViewMode === ViewModeEnum.STEREOSCOPIC ? pitch.value : 0,
        skyColor: currentSkyColor,
        viewMode: newViewMode,
        willReadFrequently: true,
      });

      // 重新添加标记
      dataHandle(chartData.value);

      // 重新设置地图样式
      let satellite = new AMapIns.TileLayer.Satellite();
      let roadNet = new AMapIns.TileLayer.RoadNet();
      if (currentStyleKey === ThemeEnum.WEIXIN) {
        mapIns.add([satellite, roadNet]);
      } else {
        mapIns.remove([satellite, roadNet]);
        mapIns.setMapStyle(
          `amap://styles/${
            currentStyleKeyCustom !== ""
              ? currentStyleKeyCustom
              : currentStyleKey
          }`
        );
      }
    } catch (error) {}
  }
});

// 监听俯仰角度变化
watch(pitch, (newPitch) => {
  if (mapIns) {
    mapIns.setPitch(newPitch);
  }
});
// 监听标记类型变化
watch(mapMarkerType, () => {
  if (mapIns && AMapIns) {
    // 重新处理数据以应用新的标记类型
    dataHandle(chartData.value);
  }
});
onMounted(() => {
  initMap(option);
});
</script>

枚举

TypeScript 复制代码
export enum ThemeEnum {
	NORMAL = 'normal',
	DARK = 'dark',
	LIGHT = 'light',
	WHITES_MOKE = 'whitesmoke',
	FRESH = 'fresh',
	GREY = 'grey',
	GRAFFITI = 'graffiti',
	MACARON = 'macaron',
	BLUE = 'blue',
	DARKBLUE = 'darkblue',
	WINE = 'wine',
	WEIXIN = 'tileLayer',
}

export enum LangEnum {
	ZH_CN = 'zh_cn',
	EN = 'en',
	ZH_EN = 'zh_en',
}

export enum ViewModeEnum {
	PLANE = '2D',
	STEREOSCOPIC = '3D',
}

export enum FeaturesEnum {
	BG = 'bg',
	POINT = 'point',
	ROAD = 'road',
	BUILDING = 'building',
}

export enum MarkerEnum {
	// 圆圈
	CIRCLE_MARKER = 'CircleMarker',
	// 定位标点
	MARKER = 'Marker',
	// 暂无
	NONE = 'none',
}
相关推荐
sanra12321 小时前
前端定位相关技巧
前端·vue
Sun_小杰杰哇1 天前
Dayjs常用操作使用
开发语言·前端·javascript·typescript·vue·reactjs·anti-design-vue
小林攻城狮1 天前
echarts 参考线实现数据项之间的差异值标注
前端·echarts
座山雕~1 天前
VUE 3
vue
@AfeiyuO1 天前
Vue3 中国地图
vue·echarts
LongtengGensSupreme1 天前
开放所有跨域 ----前端和后端
前端·后端·ajax·vue·api·jquery
极客先躯1 天前
如何修复 ECharts 鼠标交互(如 hover、点击)位置错位的问题
计算机外设·echarts·交互
困惑阿三2 天前
2025 前端技术全景图:从“夯”到“拉”排行榜
前端·javascript·程序人生·react.js·vue·学习方法
深念Y2 天前
仿B站项目 前端 4 首页 顶层导航栏
前端·vue·ai编程·导航栏·bilibili·ai开发