高德API精讲系——vue+高德API搭建前端环境页面

一、准备

  1. 申请 Key

    高德控制台 →「JSAPI」→ 创建「Web 端」Key(必须开 2.0)

    安全域名:localhost / 127.0.0.1 / 你的线上域

  2. 安装官方加载

    复制代码
    pnpm add @amap/amap-jsapi-loader
  3. 目录(建议)

    复制代码
    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>

六、常用扩展速查

  1. 标点

    JavaScript

    复制代码
    const marker = new AMap.Marker({
      position: [116.39, 39.9],
      title: '天安门'
    })
    map.add(marker)
  2. 画线

    JavaScript

    复制代码
    const polyline = new AMap.Polyline({
      path: [[116.39,39.9],[116.40,39.95]],
      strokeColor: '#3366FF',
      strokeWeight: 5
    })
    map.add(polyline)
  3. 信息窗体

    JavaScript

    复制代码
    const infoWin = new AMap.InfoWindow({
      content: '<div>Hello AMap</div>',
      offset: new AMap.Pixel(0, -30)
    })
    infoWin.open(map, marker.getPosition())
  4. 自适应显示所有覆盖物

    JavaScript

    复制代码
    map.setFitView([marker, polyline])

七、打包上线注意

  1. 域名白名单:控制台 →「Key」→ 配置「Web 端」安全域名。

  2. 体积优化:高德 2.0 默认走网络切片,无需本地 bundle;如用 Loca 可视化库需额外分包。

  3. 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>

展示效果:

相关推荐
前端大卫8 分钟前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘24 分钟前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare25 分钟前
浅浅看一下设计模式
前端
Lee川28 分钟前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试
Ticnix1 小时前
ECharts初始化、销毁、resize 适配组件封装(含完整封装代码)
前端·echarts
纯爱掌门人1 小时前
终焉轮回里,藏着 AI 与人类的答案
前端·人工智能·aigc
twl1 小时前
OpenClaw 深度技术解析
前端
崔庆才丨静觅1 小时前
比官方便宜一半以上!Grok API 申请及使用
前端
星光不问赶路人1 小时前
vue3使用jsx语法详解
前端·vue.js
天蓝色的鱼鱼1 小时前
shadcn/ui,给你一个真正可控的UI组件库
前端