高德地图(AMap)快速上手
1. 依赖与类型支持
package.json:
{
"dependencies": {
"@amap/amap-jsapi-loader": "^1.0.1"
}
}
安装命令:
yarn add @amap/amap-jsapi-loader
- @amap/amap-jsapi-loader:官方推荐的 SDK 动态加载器,用于在运行时按需加载 AMap 命名空间与插件。
全局类型扩展(src/types/amap.d.ts):
/**
* 全局类型声明(AMap / AMapUI / 安全配置)
* 目的:为使用高德地图 JS SDK 的项目提供最小可用的类型提示,避免在引用全局变量时导致 TS 报错。
*/
declare global {
interface Window {
AMapUI?: any;
AMap?: any;
_AMapSecurityConfig?: { securityJsCode?: string };
}
const AMapUI: any;
const AMap: any;
const _AMapSecurityConfig: { securityJsCode: string };
}
export {};
- Window.AMapUI:全局 AMapUI 命名空间,提供 UI 组件与工具;需在加载时配置 AMapUI 才可用。
- Window.AMap:全局 AMap 命名空间,创建地图实例的入口;依赖环境变量 VITE_AMAP_KEY 成功加载。
- Window._AMapSecurityConfig.securityJsCode:安全校验代码;如启用安全校验必须配置,建议通过环境变量注入。
2. 环境变量与安全配置
在项目 .env 中配置:
VITE_AMAP_KEY=高德Key
VITE_AMAP_SECURITY_JSCODE=高德安全密钥
注意:
- 若启用安全校验,必须在加载 SDK 前设置正确的 securityJsCode。
- 缺失或错误的 KEY 会导致 SDK 加载失败。
3. Hook 设计
核心导出:
- initMap(containerId, options?) — 在指定容器内创建地图实例;自动完成 SDK 加载与能力检测。
- destroyMap() — 解绑事件并释放地图实例,支持安全重复调用。
关键实现片段:
- 地图实例与初始化
// 地图实例引用(AMap.Map | null)
const mapInstance = shallowRef(null);
// 初始化并创建地图实例
const initMap = async (containerId: string, options?: any) => {
await getAMap();
const mapOptions = {
viewMode: '2D',
zoom: 7,
...options,
};
mapInstance.value = new AMap.Map(containerId, mapOptions);
// 绑定自定义滚轮缩放
customWheelZoom();
// 浏览器 Canvas 能力检测(不支持时给出友好提示)
if (!isCanvasSupported()) {
MessagePlugin.warning('当前浏览器不支持 Canvas,可能影响地图/热力图显示');
}
};
- SDK 动态加载与安全配置
const getAMap = async () => {
// 注入安全密钥
window._AMapSecurityConfig = {
securityJsCode: import.meta.env.VITE_AMAP_SECURITY_JSCODE || '',
};
// 已存在则跳过
if (window.AMap) return;
// 校验KEY
const key = import.meta.env.VITE_AMAP_KEY as string | undefined;
if (!key) {
console.error('缺少环境变量 VITE_AMAP_KEY,用于加载高德地图 SDK');
throw new Error('VITE_AMAP_KEY 未配置');
}
await AMapLoader.load({
key,
version: '2.0',
plugins: [],
AMapUI: {
version: '1.1',
plugins: [],
},
});
};
- 资源销毁
const destroyMap = () => {
if (!mapInstance.value) return;
mapInstance.value.off('mousewheel', mouseWheelHandler);
mapInstance.value.destroy();
mapInstance.value = null;
};
- 可选事件 - 自定义滚轮缩放
const customWheelZoom = () => {
mapInstance.value?.on('mousewheel', mouseWheelHandler);
};
const mouseWheelHandler = (e: any) => {
// 单次缩放步长
const WHEEL_STEP = 1;
// 原始滚轮增量
const deltaY = e?.originEvent?.deltaY;
// 目标级别(取整)
const deltaStep = +deltaY > 0 ? -WHEEL_STEP : WHEEL_STEP;
const current = Math.round(mapInstance.value.getZoom() + deltaStep);
// 应用缩放
mapInstance.value.setZoom(current);
};
- 可选事件 - 浏览器 Canvas 支持检测
const isCanvasSupported = () => {
const elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
4. 使用建议与注意事项
- 在组件 onMounted 中调用 initMap,并在 onBeforeUnmount 中调用 destroyMap,保证资源正确释放。
- 传入的 containerId 对应的 DOM 必须已存在且可见,否则初始化可能失败。
- 若需要额外插件,请在 AMapLoader.load 的 plugins 中补充;确保与 SDK 版本兼容。
- 安全校验启用时,确保 securityJsCode 通过环境变量正确注入。
5. 故障排查
- SDK 加载失败:检查网络、VITE_AMAP_KEY 与 securityJsCode 是否正确。
- 热力图或图形不显示:浏览器可能不支持 Canvas,或显卡/驱动限制;请更换浏览器或开启硬件加速。
6. 完整 useAmap 与 vue 代码
import AMapLoader from '@amap/amap-jsapi-loader';
import { MessagePlugin } from 'tdesign-vue-next';
import { shallowRef } from 'vue';
/**
* useAmap
* 高德地图 Hook:负责 SDK 动态加载、地图实例的创建/销毁及事件绑定。
*
* 导出方法:
* - initMap(containerId: string, options?: any): Promise<void>
* 在指定容器内创建地图实例;自动完成 SDK 加载与能力检测。
* - destroyMap(): void
* 解绑事件并释放地图实例资源;多次调用安全。
*/
export default function useAmap() {
// 地图实例
const mapInstance = shallowRef(null);
/**
* 初始化并创建地图实例
*
* @param containerId 容器 ID
* @param options 创建地图配置项
*/
const initMap = async (containerId: string, options?: any): Promise<void> => {
await getAMap();
// 创建地图实例(默认配置可按需覆盖)
const mapOptions = {
viewMode: '2D',
zoom: 7,
zooms: [7, 20],
showIndoorMap: false,
...options,
};
mapInstance.value = new AMap.Map(containerId, mapOptions);
// 绑定自定义滚轮缩放
customWheelZoom();
// 浏览器 Canvas 能力检测(不支持时给出友好提示)
if (!isCanvasSupported()) {
MessagePlugin.warning('当前浏览器不支持 Canvas,可能影响地图/热力图显示');
}
};
/**
* 确保全局 window.AMap 存在;若不存在则按需动态加载 SDK
*/
const getAMap = async () => {
// 注入安全密钥
window._AMapSecurityConfig = {
securityJsCode: import.meta.env.VITE_AMAP_SECURITY_JSCODE || '',
};
// 已存在则跳过加载
if (window.AMap) return;
// 校验 KEY
const key = import.meta.env.VITE_AMAP_KEY as string | undefined;
if (!key) {
console.error('缺少环境变量 VITE_AMAP_KEY,用于加载高德地图 SDK');
throw new Error('VITE_AMAP_KEY 未配置');
}
// 动态加载 SDK(含常用插件与 AMapUI)
try {
await AMapLoader.load({
key,
version: '2.0',
plugins: [],
AMapUI: {
version: '1.1',
plugins: [],
},
});
} catch (err) {
console.error('高德地图 SDK 加载失败', err);
throw err;
}
};
/**
* 浏览器 Canvas 能力检测
* 返回:boolean(true 表示支持;false 表示不支持)
*/
const isCanvasSupported = () => {
const elem = document.createElement('canvas');
return !!(elem.getContext && elem.getContext('2d'));
};
/**
* 绑定自定义滚轮缩放事件
* - 说明:使用原生滚轮事件的增量控制地图缩放级别,替代默认缩放行为。
*/
const customWheelZoom = () => {
mapInstance.value?.on('mousewheel', mouseWheelHandler);
};
/**
* 地图滚轮缩放事件处理器
*
* - deltaY > 0 视为向下滚动(缩小);否则视为向上滚动(放大)。
* - 每次滚动调整一个整数级别,避免小数缩放造成的抖动。
*/
const mouseWheelHandler = (e: any) => {
// 单次缩放步长
const WHEEL_STEP = 1;
// 原始滚轮增量
const deltaY = e?.originEvent?.deltaY;
// 目标级别(取整)
const deltaStep = +deltaY > 0 ? -WHEEL_STEP : WHEEL_STEP;
const current = Math.round(mapInstance.value.getZoom() + deltaStep);
// 应用缩放
mapInstance.value.setZoom(current);
};
/**
* 销毁地图实例
* 行为:
* - 解绑自定义滚轮事件;
* - 释放地图实例资源;
*/
const destroyMap = () => {
if (!mapInstance.value) return;
mapInstance.value.off('mousewheel', mouseWheelHandler);
mapInstance.value.destroy();
mapInstance.value = null;
};
return {
// 响应式引用
mapInstance,
// 方法
initMap,
destroyMap,
};
}
<script setup lang="ts">
import { onBeforeUnmount, onMounted, ref } from 'vue';
import useAmap from './hooks/useAmap';
const { mapInstance, initMap, destroyMap } = useAmap();
onMounted(() => {
initMap('map_container');
});
onBeforeUnmount(() => {
// 组件卸载时销毁地图实例
destroyMap();
});
</script>
<template>
<div class="view-wrapper">
<!-- 地图 -->
<div id="map_container" class="map-container"></div>
<!-- 悬浮在地图上的大屏组件 -->
<div id="screenId" class="screen-wrapper"></div>
</div>
</template>
<style scoped lang="less">
.view-wrapper {
position: relative;
.map-container {
position: absolute;
width: 100vw;
height: 100vh;
}
.screen-wrapper {
position: relative;
pointer-events: none;
}
}
</style>
960

被折叠的 条评论
为什么被折叠?



