Skip to content

加载高德地图

使用 leaflet 与 vue 加载高德地图、实现图层切换。

示例

安装依赖

shell
# gcoord 是一个处理地理坐标系的JS库
# 用来修正百度地图、高德地图及其它互联网地图坐标系不统一的问题。
pnpm i gcoord

代码实现

vue
<script setup>
import { onMounted, onUnmounted, ref } from 'vue';
import { useGaoDeMap } from '../../composables/useGaoDeMap';

const mapObj = ref();

const { initMap, setGaoDeLayer } = useGaoDeMap();

// 在 onMounted 中初始化地图
onMounted(() => {
  mapObj.value = initMap();

  // 设置底图
  setGaoDeLayer();
});

const removeMap = () => {
  if (mapObj.value) {
    mapObj.value.remove();
  }
};

// 在组件卸载时删除地图
onUnmounted(() => {
  removeMap();
});
</script>

<template>
  <div id="map"></div>

  <div class="buts">
    <button class="c-button" @click="setGaoDeLayer('02')">电子地图</button>
    <button class="c-button" @click="setGaoDeLayer('01')">影像地图</button>
  </div>
</template>

<style lang="scss" scoped>
#map {
  height: 40vh;
}

.buts {
  margin-top: 10px;
}
</style>
js
import { ref } from 'vue';
import gcoord from 'gcoord';

/**
 * todo 项目使用请放开 leaflet 引入,这里注释是因为:
 * 直接引入 leaflet 打包会抛出 window is not undefined,因为 vitePress 打包是在node环境运行。
 * 所以在 vitePress 配置了自动加载。
 */
// import L from 'leaflet';

export const useGaoDeMap = () => {
  // 初始化高德图层设置
  const initGaoDeTileLayer = () => {
    L.TileLayer.GaoDeTileLayer = L.TileLayer.extend({
      initialize: function (param, options) {
        const templateUrl =
          '//wprd0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&{p}';
        // var templateUrl = "//webst{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&{p}"
        options = L.extend(
          {
            p: param,
            subdomains: '1234',
            minZoom: 0,
            maxZoom: 20,
            minNativeZoom: 1,
            maxNativeZoom: 18,
            attribution: '&copy; <a href="https://ditu.amap.com/">高德地图</a>'
          },
          options
        );
        L.TileLayer.prototype.initialize.call(this, templateUrl, options);
      },
      _setZoomTransform: function (level, center, zoom) {
        center = L.latLng(
          gcoord.transform([center.lat, center.lng], gcoord.WGS84, gcoord.GCJ02)
        );
        L.TileLayer.prototype._setZoomTransform.call(this, level, center, zoom);
      },
      _getTiledPixelBounds: function (center) {
        center = L.latLng(
          gcoord.transform([center.lat, center.lng], gcoord.WGS84, gcoord.GCJ02)
        );
        return L.TileLayer.prototype._getTiledPixelBounds.call(this, center);
      }
    });
  };

  // 初始化地图
  const mapObj = ref();
  const initMap = (mapDomId = 'map') => {
    initGaoDeTileLayer();
    // leaflet 默认投影是 L.CRS.EPSG3857	与高德相同,所以无需设置
    const map = L.map(mapDomId, {
      center: [32.0237855, 118.8075675],
      zoom: 11,
      minZoom: 7,
      maxZoom: 20
    });

    // todo 直接导出 mapObj.value 访问方法会有问题
    mapObj.value = map;
    return map;
  };

  // 根据类型获取不同底图参数
  const getGaoDeLayerByType = (type) => {
    const layerObj = {
      '01': {
        opts: 'lang=zh_cn&style=6&ltype=0&scl=0&size=0',
        info: '影像底图'
      },
      '02': {
        opts: 'lang=zh_cn&style=7&ltype=0&scl=0&size=0',
        info: '电子地图底图'
      }
    };

    return new L.TileLayer.GaoDeTileLayer(layerObj[type].opts, {});
  };

  // 设置图层
  const curMapLayer = ref();
  const setGaoDeLayer = (type = '02') => {
    if (curMapLayer.value) {
      curMapLayer.value.remove(mapObj.value);
      curMapLayer.value = null;
    }

    curMapLayer.value = getGaoDeLayerByType(type);
    curMapLayer.value.addTo(mapObj.value);
  };

  return {
    initMap,
    setGaoDeLayer
  };
};

贡献者

Released under the MIT License.