一、准备
-
申请 Key
高德控制台 →「JSAPI」→ 创建「Web 端」Key(必须开 2.0)
安全域名:localhost / 127.0.0.1 / 你的线上域
-
安装官方加载
pnpm add @amap/amap-jsapi-loader -
目录(建议)
src ├─ components │ ├─ AMapView.vue // 地图容器 │ └─ LayerControl.vue // 图层切换条 ├─ composables │ └─ useAMap.js // 地图初始化逻辑复用 └─ App.vue
二、核心逻辑封装(composables/useAMap.js)
JavaScript
import { ref, shallowRef, onBeforeUnmount } from 'vue'
import AMapLoader from '@amap/amap-jsapi-loader'
export const mapKey = '你的key'
export const mapVersion = '2.0'
export function useAMap() {
const map = shallowRef(null) // 地图实例
const AMap = shallowRef(null) // 命名空间
const pending = ref(true)
// 图层缓存
const layers = {
satellite: null,
roadNet: null,
traffic: null,
standard: null
}
async function initAMap(containerId, config = {}) {
pending.value = true
try {
AMap.value = await AMapLoader.load({ key: mapKey, version: mapVersion })
map.value = new AMap.value.Map(containerId, {
zoom: 11,
center: [116.397428, 39.90923],
...config
})
// 预创建图层
layers.satellite = new AMap.value.TileLayer.Satellite()
layers.roadNet = new AMap.value.TileLayer.RoadNet()
layers.traffic = new AMap.value.TileLayer.Traffic()
layers.standard = new AMap.value.TileLayer() // 默认空白底图
// 默认只显示标准底图
map.value.add(layers.standard)
} finally {
pending.value = false
}
}
function toggleLayer(key, show) {
const layer = layers[key]
if (!layer || !map.value) return
show ? map.value.add(layer) : map.value.remove(layer)
}
onBeforeUnmount(() => map.value && map.value.destroy())
return { map, AMap, pending, initAMap, toggleLayer, layers }
}
三、地图容器组件(components/AMapView.vue)
vue
<template>
<div ref="containerRef" class="map-container">
<slot :map="map" :AMap="AMap" :pending="pending" />
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { useAMap } from '@/composables/useAMap'
const containerRef = ref(null)
const { map, AMap, pending, initAMap } = useAMap()
onMounted(() => initAMap(containerRef.value))
defineExpose({ map, AMap, pending })
</script>
<style scoped>
.map-container {
width: 100%;
height: 100vh;
}
</style>
四、图层切换条(components/LayerControl.vue)
vue
<template>
<div class="layer-bar">
<label>
<input type="checkbox" v-model="sat" @change="toggleLayer('satellite', sat)" />
卫星
</label>
<label>
<input type="checkbox" v-model="road" @change="toggleLayer('roadNet', road)" />
路网
</label>
<label>
<input type="checkbox" v-model="traffic" @change="toggleLayer('traffic', traffic)" />
实时路况
</label>
</div>
</template>
<script setup>
import { ref, inject } from 'vue'
const toggleLayer = inject('toggleLayer') // 父组件提供
const sat = ref(false), road = ref(false), traffic = ref(false)
</script>
<style scoped>
.layer-bar {
position: absolute;
top: 20px;
right: 20px;
background: #fff;
padding: 8px 12px;
border-radius: 4px;
box-shadow: 0 2px 4px rgba(0,0,0,.2);
z-index: 1;
}
label + label { margin-left: 12px; }
</style>
五、根组件(App.vue)
vue
<template>
<AMapView ref="mapView">
<template #default="{ map, AMap, pending }">
<LayerControl v-if="!pending" />
<!-- 后续可继续扩展:绘制、搜索、信息窗体等 -->
</template>
</AMapView>
</template>
<script setup>
import AMapView from '@/components/AMapView.vue'
import LayerControl from '@/components/LayerControl.vue'
import { provide, ref } from 'vue'
const mapView = ref(null)
provide('toggleLayer', (key, show) => {
mapView.value.toggleLayer(key, show)
})
</script>
六、常用扩展速查
-
标点
JavaScript
const marker = new AMap.Marker({ position: [116.39, 39.9], title: '天安门' }) map.add(marker) -
画线
JavaScript
const polyline = new AMap.Polyline({ path: [[116.39,39.9],[116.40,39.95]], strokeColor: '#3366FF', strokeWeight: 5 }) map.add(polyline) -
信息窗体
JavaScript
const infoWin = new AMap.InfoWindow({ content: '<div>Hello AMap</div>', offset: new AMap.Pixel(0, -30) }) infoWin.open(map, marker.getPosition()) -
自适应显示所有覆盖物
JavaScript
map.setFitView([marker, polyline])
七、打包上线注意
-
域名白名单:控制台 →「Key」→ 配置「Web 端」安全域名。
-
体积优化:高德 2.0 默认走网络切片,无需本地 bundle;如用
Loca可视化库需额外分包。 -
TypeScript 支持
pnpm add -D @types/amap-js-api并在
tsconfig.json里"types": ["amap-js-api"]。
八、截图效果复现
运行
pnpm dev
浏览器打开 http://localhost:5173 即可看到:
-
右侧悬浮"卫星 / 路网 / 实时路况"切换条;
-
点击勾选 → 图层即时叠加/移除;
-
后续只要在
<AMapView>插槽里继续写业务(点线面、搜索、聚合)即可。
完整代码:
html
<template>
<div class="page-container">
<div id="container"></div>
</div>
</template>
<script>
import AMapLoader from '@amap/amap-jsapi-loader';
export default {
name: "LayerManage",
data() {
return {
map: null,
satelliteLayer: null,
roadNetLayer: null
};
},
methods: {
initMap() {
AMapLoader.load({
key: "1e31659e58fa7666fe0d08f4487ec5c2", // 记得替换为实际申请的有效key
version: "2.0"
}).then((AMap) => {
this.map = new AMap.Map('container', {
zoom: 12,
center: [114.091135, 32.148518]
});
// 构造官方卫星、路网图层
this.satelliteLayer = new AMap.TileLayer.Satellite();
// this.roadNetLayer = new AMap.TileLayer.RoadNet();
// 批量添加图层
this.map.add([this.satelliteLayer, this.roadNetLayer]);
}).catch(e => {
console.log(e);
});
},
addSatelliteLayer() {
this.map.add(this.satelliteLayer);
},
removeSatelliteLayer() {
this.map.remove(this.satelliteLayer);
},
addRoadNetLayer() {
this.map.add(this.roadNetLayer);
},
removeRoadNetLayer() {
this.map.remove(this.roadNetLayer);
}
},
mounted() {
this.initMap();
}
};
</script>
<style>
html,
body,
#container {
width: 100%;
height: 125%;
}
.page-container {
width: 100%;
}
.input-card {
width: 24rem;
}
.input-item {
margin-bottom: 10px;
}
.btn {
padding: 5px 10px;
}
</style>
展示效果:



