vue项目 高德地图实现区域多个标点并通过半径距离以此点绘制多个圆(circle),动态显示隐藏圆;实现根据经纬度获取中文地址,根据地址获取经纬度;地图控件显示隐藏

最终效果

在这里插入图片描述

一、需求

最近公司有这样一个需求,指定一个区域根据一个距离测算需要开放多少个门店才能覆盖整个指定区域(暂不考虑人口密集、山区等因素——大概估算);因此稍微了解了一下,高德地图的API,记录一下常用高德地图进行定位、标点(自定义标点)、测距、绘制矢量图(圆、多边形等)、根据经纬度获取中文地址、根据地址获取经纬度等等功能。

二、前期准备,需申请key及安全秘钥

其步骤可自行百度
在这里插入图片描述

三、实际项目使用(适用于vue2与vue3项目)

以下实现的效果都是在index.html中引入的方式来实现的

也可以使用:@amap/amap-jsapi-loadervue-amap

1、index.html页面的<head>标签中添加以下代码

<!-- 解决逆地理编码,根据经纬度获取地址信息 -->
  <script type="text/javascript">
    window._AMapSecurityConfig = {
      securityJsCode: '所申请的安全密钥', //所申请的安全密钥 注意这是安全密钥而不是key
    }
  </script>
  <!--同步加载AMap-->
  <script
    src='https://webapi.amap.com/maps?v=2.0&key=自己申请的key&&plugin=AMap.Scale,AMap.HawkEye,AMap.ToolBar,AMap.ControlBar,AMap.PlaceSearch,AMap.DistrictSearch,AMap.HeatMap,AMap.3DTilesLayer,AMap.IndoorMap,AMap.MoveAnimation,AMap.ElasticMarker,AMap.MarkerCluster,AMap.IndexCluster,AMap.MouseTool,AMap.BezierCurveEditor,AMap.RectangleEditor,AMap.CircleEditor,AMap.EllipseEditor,AMap.GeoJSON,AMap.PolylineEditor,AMap.PolygonEditor,AMap.AutoComplete,AMap.Driving,AMap.Walking,AMap.Riding,AMap.Transfer,AMap.Geocoder,AMap.GraspRoad,AMap.StationSearch,AMap.LineSearch,AMap.ArrivalRange,AMap.CitySearch,AMap.Geolocation,AMap.Weather,AMap.RangingTool'></script>

2、实现具体功能

1、左击获取经纬度,并根据经纬度回显地址

在这里插入图片描述

<template>
  <t-layout-page class="map_localization">
    <div id="container"></div>
    <div class="input-item">
      <div class="title">左击获取经纬度</div>
      <el-input v-model="lnglat">
        <template slot="prepend">经纬度</template>
      </el-input>
      <el-input style="margin-top:5px;" v-model="address">
        <template slot="prepend">地址</template>
      </el-input>
    </div>
  </t-layout-page>
</template>
<script>
export default {
  name: 'MapLocalization',
  data() {
    return {
      map: null,
      lnglat: '113.276517,23.151382',
      address: ''
    }
  },
  mounted() {
    //调用地图初始化方法
    this.initAMap()
    this.regeoCode()
  },
  methods: {
    initAMap() {
      this.map = new AMap.Map('container', {
        resizeEnable: true,
        zoom: 15,
        center: [113.276517, 23.151382]
      });
      //使用CSS默认样式定义地图上的鼠标样式
      this.map.setDefaultCursor("pointer");
      //绑定地图点击事件
      this.map.on('click', (e) => {
        this.lnglat = e.lnglat.getLng() + ',' + e.lnglat.getLat();
        this.regeoCode()
      })
    },
    // 逆地理编码,根据经纬度获取地址信息
    regeoCode() {
      this.map.clearMap();
      let lnglat = this.lnglat.split(',');
      let marker = new AMap.Marker();
      let geocoder = new AMap.Geocoder({
        city: "020", //城市设为广州,默认:“全国”
        radius: 1000, //范围,默认:500
        // extensions: 'all'
      });
      this.map.add(marker);
      marker.setPosition(lnglat);
      geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.regeocode) {
          this.address = result.regeocode.formattedAddress;
        } else {
          this.$message.error('根据地址查询位置失败,请重新选择!');
        }
      });
    }
  }
}
</script>

<style lang="scss" scoped>
.map_localization {
  position: relative;
  #container {
    width: 100%;
    height: 100%;
  }
  .input-item {
    position: absolute;
    background: white;
    padding: 15px;
    right: 30px;
    bottom: 10px;
    .title {
      font-weight: bold;
      font-size: 16px;
      margin-bottom: 10px;
    }
  }
}
</style>

2、测距—默认样式测距、自定义样式测距

在这里插入图片描述

<template>
  <t-layout-page class="map_localization">
    <div id="container"></div>
    <div class="cursor-item">
      <div class="title">测距</div>
      <el-button round size="mini" @click="defaultStyle"
        >默认样式测距</el-button
      >
      <el-button round size="mini" @click="customStyle"
        >自定义样式测距</el-button
      >
    </div>
  </t-layout-page>
</template>
<script>
export default {
  name: "MapLocalization",
  data() {
    return {
      map: null,
      ruler1: null,
      ruler2: null
    };
  },
  mounted() {
    //调用地图初始化方法
    this.initAMap();
  },
  methods: {
    initAMap() {
      this.map = new AMap.Map("container", {
        resizeEnable: true,
        zoom: 15,
        center: [113.276517, 23.151382]
      });
      //默认样式
      this.ruler1 = new AMap.RangingTool(this.map);
      //自定义样式
      let startMarkerOptions = {
        icon: new AMap.Icon({
          size: new AMap.Size(19, 31), //图标大小
          imageSize: new AMap.Size(19, 31),
          image: "//webapi.amap.com/theme/v1.3/markers/b/start.png"
        }),
        offset: new AMap.Pixel(-9, -31)
      };
      let endMarkerOptions = {
        icon: new AMap.Icon({
          size: new AMap.Size(19, 31), //图标大小
          imageSize: new AMap.Size(19, 31),
          image: "//webapi.amap.com/theme/v1.3/markers/b/end.png"
        }),
        offset: new AMap.Pixel(-9, -31)
      };
      let midMarkerOptions = {
        icon: new AMap.Icon({
          size: new AMap.Size(19, 31), //图标大小
          imageSize: new AMap.Size(19, 31),
          image: "//webapi.amap.com/theme/v1.3/markers/b/mid.png"
        }),
        offset: new AMap.Pixel(-9, -31)
      };
      let lineOptions = {
        strokeStyle: "solid",
        strokeColor: "#FF33FF",
        strokeOpacity: 1,
        strokeWeight: 2
      };
      let rulerOptions = {
        startMarkerOptions: startMarkerOptions,
        midMarkerOptions: midMarkerOptions,
        endMarkerOptions: endMarkerOptions,
        lineOptions: lineOptions
      };
      this.ruler2 = new AMap.RangingTool(this.map, rulerOptions);
      //使用CSS默认样式定义地图上的鼠标样式
      this.map.setDefaultCursor("pointer");
    },
    //默认样式测距
    defaultStyle() {
      this.ruler2.turnOff();
      this.ruler1.turnOn();
    },
    //自定义样式测距
    customStyle() {
      this.ruler1.turnOff();
      this.ruler2.turnOn();
    }
  }
};
</script>

<style lang="scss" scoped>
.map_localization {
  position: relative;
  #container {
    width: 100%;
    height: 100%;
  }

  .cursor-item {
    position: absolute;
    background: white;
    padding: 5px 20px 10px;
    right: 340px;
    bottom: 170px;
    .title {
      font-weight: bold;
      font-size: 16px;
      margin-bottom: 10px;
    }
    .mouseStyle {
      display: block;
      padding: 5px 20px 10px;
    }
  }
}
</style>

3、绘制矢量图(圆、多边形等)

1、绘制多边形
1、效果

在这里插入图片描述

2、关键代码

selectedOptions是选择省市区的编码数组

        let keyword;
        if (this.selectedOptions.length > 0) {
          keyword = this.selectedOptions[this.selectedOptions.length - 1];
        }
        // 创建行政区查询对象
        let district = new AMap.DistrictSearch({
          // 返回行政区边界坐标等具体信息
          extensions: "all"
          // subdistrict: 1
          // 设置查询行政区级别为 区
          level: 'district'
        });
        district.search(keyword, (status, result) => {
          if (result.districtList) {
            // 获取边界信息
            let bounds = result.districtList[0].boundaries;
            let polygons = [];
            if (bounds) {
              for (let i = 0, l = bounds.length; i < l; i++) {
                //生成行政区划polygon
                let polygon = new AMap.Polygon({
                  map: this.map,
                  strokeWeight: 1,
                  path: bounds[i],
                  fillOpacity: 0.7,
                  fillColor: "#CCF3FF",
                  strokeColor: "#CC66CC"
                });
                polygons.push(polygon);
              }
              // 地图自适应
              this.map.setFitView();
            }
          } else {
            this.map.setFitView();
          }
        });
2、绘制圆
1、效果

在这里插入图片描述

2、关键代码

this.circles是后台提供绘制圆形的经纬度数据

  // 添加Circle
    addCircle() {
      this.circleList = [];
      for (let i = 0; i < this.circles.length; i += 1) {
        let center = this.circles[i].center;
        let circle = new AMap.Circle({
          center: center,
          radius: ((this.radius - 0) * 1000) / 2, // 半径
          strokeColor: "#F33", // 线颜色
          // strokeColor: this.rgb(),  // 线颜色
          zIndex: 101,
          strokeOpacity: 1, //线透明度
          strokeWeight: 3, //线粗细度
          bubble: true, // 是否将覆盖物的鼠标或touch等事件冒泡到地图上
          fillColor: "#7c7cfb", //填充颜色
          fillOpacity: 0.35 //填充透明度
        });
        circle.setMap(this.map);
        this.circleList.push(circle);
      }
    },
    // 动态显示和隐藏圆
    changeShowCircle() {
      if (this.isShowCircle) {
        this.circleList.map(item => {
          item.show();
        });
      } else {
        this.circleList.map(item => {
          item.hide();
        });
      }
    },

四、vue3+vite+ts项目打包需要解决以下问题:

1、问题

因为是index.html页面的<head>标签中引入的高德地图会出现

1、new AMap在ts语法报错 且打包时也报错在这里插入图片描述

2、需要用window定义AMap报错

在这里插入图片描述

2、解决办法

问题2解决办法在.d.ts文件中加上

declare interface Window {
  AMap: any;
}

问题1的解决办法,在utils下新建一个map.ts文件

export function MapLoader() {
  return new Promise(resolve => {
    if (window.AMap) {
      resolve(window.AMap);
    }
  });
}

页面使用

import { MapLoader } from "@/utils/map";
MapLoader().then((AMap: any) => {
state.map = new AMap.Map("container", {
      // resizeEnable: true,
      viewMode: "3D",
      zoom: 12,
      center: [113.265862, 23.126124]
    });
})

解决vite打包没有webpack externals:{‘AMap’: ‘AMap’}配置

pnpm add -D vite-plugin-resolve-externals

vite.config.ts 文件中引入

import resolveExternalsPlugin from 'vite-plugin-resolve-externals'
  plugins: [
  ...
    resolveExternalsPlugin({
      AMap: 'AMap'
    })
  ],

五、demo地址

Vue3项目gitHub组件地址

Vue3项目gitee码云组件地址

Vue3项目在线预览地址


Vue2项目gitHub组件地址

Vue2项目gitee码云组件地址

Vue2项目在线预览地址

六、相关文章

基于ElementUi或AntdUI再次封装基础组件文档


基于Element-plus再次封装基础组件文档(vue3+ts)

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wocwin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值