高德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>

展示效果:

相关推荐
西西偷西瓜2 小时前
Trae IDE 读取并解析接口文档:trae-swagger-mcp 插件开发分享
前端·ide·自动化·yapi·ai编程
木易 士心2 小时前
JavaScript 中的精度丢失与分摊不平问题及解决方案
开发语言·javascript·ecmascript
PineappleCoder10 小时前
性能数据别再瞎轮询了!PerformanceObserver 异步捕获 LCP/CLS,不卡主线程
前端·性能优化
PineappleCoder10 小时前
告别字体闪烁 / 首屏卡顿!preload 让关键资源 “高优先级” 提前到
前端·性能优化
m0_4711996311 小时前
【vue】通俗详解package-lock文件的作用
前端·javascript·vue.js
GIS之路11 小时前
GDAL 读取KML数据
前端
今天不要写bug12 小时前
vue项目基于vue-cropper实现图片裁剪与图片压缩
前端·javascript·vue.js·typescript
用户479492835691512 小时前
记住这张时间线图,你再也不会乱用 useEffect / useLayoutEffect
前端·react.js