vue项目中使用高德地图

vue中使用高德地图

  1. 使用高德官方案例

    [概述-地图 JS API 高德地图API (amap.com)](https://lbs.amap.com/api/javascript-api/summary/)
  2. 使用第三方基于高德官方开放api的二次封装

    1. vue-amap

      [组件 vue-amap (elemefe.github.io)](https://elemefe.github.io/vue-amap/#/)

      饿了么团队封装的组件, 首推, 有时间了好好研究一下

    2. AMap-Vue

      AMap-Vue (gitee.io)

      使用者较少, 但用起来也还舒服, 文档相对简陋, 但他提供了扩展自定义组件的方法(还是比较舒服的),本次主要使用这个.

      • 至于如何安装官方文档已经说明了: [介绍 AMap-Vue (gitee.io)](https://jimnox.gitee.io/amap-vue/intro/)
      • 在AMap-Vue基础上封装的定位到当前城市的按钮组件

        <template>
          <!-- 定位按钮(需要放在 <amap></amap>标签内) -->
          <div class="amap-geolocation" @click="resetLocation">
            <el-button type="primary" icon="el-icon-map-location" />
          </div>
        </template>
                
        <script>
        import { withAmap, loadPlugins } from '@amap/amap-vue'
        export default {
          name: 'Amapgeolocation',
          mixins: [withAmap],
          data() {
            return {}
          },
                
          async mounted() {
            // 加载插件与初始化---精确定位与城市定位
            await loadPlugins(['AMap.Geolocation', 'AMap.CitySearch'])
            this.gl = new AMap.Geolocation()
            this.cs = new AMap.CitySearch()
          },
                
          methods: {
            //   获取定位
            resetLocation() {
              let that = this
              this.cs.getLocalCity(function(status, result) {
                if (status === 'complete' && result.info === 'OK') {
                  // 查询成功,result即为当前所在城市信息
                  console.log(result)
                  that.$map.setCenter([(result.bounds.northEast.lng + result.bounds.southWest.lng) / 2, (result.bounds.northEast.lat + result.bounds.southWest.lat) / 2])
                  that.$map.setZoom(14)
                }
              })
            }
          }
        }
        </script>
                
        <style lang="scss" scoped>
        .amap-geolocation {
          position: absolute;
          right: 20px;
          top: 20px;
          width: 32px;
          height:32px;
          display: flex;
          flex-direction: column;
          justify-content: center;
          background-image: none;
          border-radius: 10%;
                
          &:hover {
            background-color: #f0f0f0;
          }
          .el-button {
            width: 32px;
            height:32px;
            font-size: 16px;
            padding: 0;
          }
        }
        </style>
                
        
      • 在AMap-Vue基础上封装的 支持聚合的marker点 组件

        使用需要为组件传入markerData, markerData需要包含定位点数组 lnglat = [lat, lng] (如果需要使用infowindow和label则把需要的参数也一起放进markerData里), 组件中的infowindow和marker的label可按需选择是否保留

        markerData : [
            lnglat: [,],
            sex: '', // 额外的数据
            age: '' // 额外的数据
        ]
        
        <template>
          <div>
            <amap-marker-cluster
              key="custom-cluster"
              :data="markerData"
              key-prop="poiid"
              :marker-options="getMarkerOptions"
              :cluster-options="getClusterOptions"
              :grid-size="options.gridSize"
              :average-center="options.averageCenter"
            >
              <!-- 多个marker时的样式 -->
              <template v-slot:cluster="context">
                <div :style="getClusterStyle(context)" @click="resetZoom(context)">
                          
                </div>
              </template>
              <!-- 单个marker时的样式 -->
              <template v-slot:marker="point">
                <div class="custom-marker" :class="{warning : point.warning}" @click="clickMarker(point)" />
              </template>
            </amap-marker-cluster>
            <amap-marker
              v-if="current"
              :key="current.memberId"
              :position="[current.lnglat.lng, current.lnglat.lat]"
              :label="{
                content: current === hover ? current.memberName : '',
                direction: 'bottom',
              }"
              :z-index="current === hover ? 110 : 100"
              @click="clickMarker(current, current.memberName)"
            />
            <amap-info-window
              v-if="current && activeAoi"
              :position="activeAoi.position"
              :offset="[0, -30]"
              auto-move
            ><div>
              <div>性别: </div>
              <div>年龄: </div>
            </div>
            </amap-info-window>
          </div>
        </template>
                
        <script>
        import { withAmap } from '@amap/amap-vue'
        function interpolate(u, begin, end) {
          if (u < 0) u = 0
          if (u > 1) u = 1
          u = Math.pow(u, 1 / 10)
          return u * (end - begin) + begin
        }
        export default {
          name: 'Comamapmarker',
          mixins: [withAmap],
          props: {
            markerData: {
              type: Array,
              default: []
            }
          },
          data() {
            return {
              warning: 'warning',
              hover: null,
              activeAoi: '',
              options: {
                gridSize: 40,
                averageCenter: true,
                zoomOnClick: true
              },
              current: null
            }
          },
          mounted() {},
                
          methods: {
            // 点击点标记
            clickMarker(poi, value) {
              console.log('此标记点的信息', poi, value)
                
              poi.position = [poi.lnglat.lng, poi.lnglat.lat]
              this.activeAoi = this.activeAoi === '' ? poi : ''
              this.hover = this.hover === null ? poi : null
              this.current = poi
                
              console.log('activeAoi: ', this.activeAoi)
              // 通知父组件当前选中的是哪个marker
              this.$emit('markerValue', value)
            },
            // 移除地图覆盖物
            fitView() {
              requestAnimationFrame(() => {
                // todo 移除地图覆盖物
                this.$map.setFitView(null, false, [0, 0, 300, 0])
              })
            },
            // 根据经纬度查询地址信息
            getAddress(lng, lat) {
              let lnglat = [lng, lat]
              this.gc.getAddress(lnglat, function(status, result) {
                if (status === 'complete' && result.info === 'OK') {
                  // result为对应的地理位置详细信息
                  console.log(result.regeocode.formattedAddress)
                }
              })
            },
                
            getMarkerOptions(point) {
              return {
                offset: [0, 0]
              }
            },
            getClusterOptions(context) {
              const size = Math.round(
                30 + Math.pow(context.count / this.markerData.length, 1 / 5) * 20
              )
              return {
                offset: [-size / 2, -size / 2]
              }
            },
            getClusterStyle(context) {
              const u = context.count / this.markerData.length
              const hue = ~~interpolate(u, 90, 0)
              const size = ~~interpolate(u, 30, 50)
              return {
                backgroundColor: `hsla(${hue}, 100%, 50%, 0.7)`,
                width: `${size}px`,
                height: `${size}px`,
                lineHeight: `${size}px`,
                borderRadius: `${size / 2}px`,
                border: `1px solid hsla(${hue}, 100%, 40%, 1)`,
                boxShadow: `0 0 1px hsla(${hue}, 100%, 50%, 1)`,
                color: `hsla(${hue}, 100%, 20%, 1)`,
                fontSize: '14px',
                textAlign: 'center'
              }
            },
            // 地图尺寸放大
            resetZoom(context) {
              console.log(context)
              // todo 设置地图中心点
              this.$map.setCenter(context.marker._position)
              // todo 重设设置地图zoom
              let zoom = this.$map.getZoom()
              this.$map.setZoom(++zoom)
            }
          }
        }
        </script>
                
        <style lang="scss" scoped>
                
        // myMarkers {
        .map-container {
          width: 100%;
          height: 500px;
        }
        .custom-marker {
          $color: hsla(128, 100%, 58%, 0.8);
          background-color: $color;
          border: 1px solid darken($color, 50%);
          box-sizing: border-box;
          $size: 20px;
          height: $size;
          width: $size;
          border-radius: $size / 2;
          transform: translate3d(-50%, -50%, 0);
        }
        .onlyMarker {
          display: flex;
          flex-direction: row;
          justify-content: center;
        }
        .amap-marker-label {
          // position: absolute;
          z-index: 2;
          border: 1px solid #00f;
          background-color: #fff;
          cursor: default;
          padding: 3px;
          width: max-content; /* 元素内容固有的(intrinsic)合适宽度。 */
          max-width: 120px;
          word-break: break-word; /* 文本行的任意字内断开 */
          white-space: normal; /* 超出最大宽度换行 */
          font-size: 16px;
          line-height: 1.5;
        }
        .info-window-content {
          position: relative;
          width: 220px;
          z-index: 4000;
        }
        .warning {
          background-color: red;
        }
        // }
        </style>
        <style lang="scss">
        // 让marker点标记的内容自动换行
        .amap-marker-label {
          // margin: 15px;
          max-width: 120px;
          width: max-content; /* 元素内容固有的(intrinsic)合适宽度。 */
          white-space: normal;
          font-size: 16px;
          line-height: 1.5;
        }
        .amap-info-content {
          max-width: 200px;
          white-space: normal;
          z-index: 1001;
        }
        </style>
                
        
      • 作者提供的封装好的组件:

        <!-- 地图类型 -->
                <!-- <amap-map-type /> -->
                <!-- 缩略图 -->
                <!-- <amap-hawk-eye /> -->
                <!-- 指南针 -->
                <!-- <amap-control-bar /> -->
                <!-- 缩放工具条 -->
                <amap-tool-bar />
        <!-- 比例尺 属性配置可参考官方文档  position是组件停靠位置, offset是组件相对于地图的偏移 -->
                <amap-scale :offset="[60, 30]" position="RB" />