如何封装一款地图组件

723 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

TIP 👉 道高一尺,魔高一丈。吴承恩《西游记》

前言

在我们日常项目开发中,我们可能会会涉及到地图功能,所以封装了这款地图组件。

地图定位组件

属性

1. value
  • 位置信息
  • 值为对象
  • 值示例:
{
    address: '北京市朝阳区奥运村街道奥林匹克森林公园奥林匹克森林公园南园',
    lng: 116.389006,
    lat: 40.015535
}
2. editable
  • 是否可编辑(即修改位置)
  • 值为布尔类型
  • 默认值为 false
样式要求
  • 组件外面需要包裹可以相对定位的元素,增加样式:position: relative

示例

<template>
<div class="amap-demo">
  <ul class="form-list">
    <li class="form-item" @click="popupBox1">
      <div class="item-content">
        <label>位置查看:</label>
        <span>{{value1 && value1.address}}</span>
      </div>
      <div class="arrow">
        <Icon name="right-arrow"></Icon>
      </div>
    </li>
    <li class="form-item" @click="popupBox2">
      <div class="item-content">
        <label>位置定位:</label>
        <span>{{value2 && value2.address}}</span>
      </div>
      <div class="arrow">
        <Icon name="right-arrow"></Icon>
      </div>
    </li>
  </ul>
</div>
</template>
<script>
import popupFullBox from '@/components/m/fullBox'
import AMap from '@/components/base/amap/AMap.vue'

export default {
  name: 'AMapDemoM',
  data () {
    return {
      value1: {
        address: '北京市朝阳区奥运村街道奥林匹克森林公园奥林匹克森林公园南园',
        lng: 116.389006,
        lat: 40.015535
      },
      value2: null
    }
  },
  methods: {
    popupBox1 () {
      popupFullBox({
        title: '位置查看',
        scroll: false,
        content: AMap,
        contentProps: {
          value: this.value1
        }
      })
    },
    popupBox2 () {
      popupFullBox({
        title: '地图定位',
        scroll: false,
        content: AMap,
        contentProps: {
          value: this.value2,
          editable: true
        },
        contentEvents: {
          changePosition: (v) => {
            this.value2 = v
          }
        }
      })
    }
  }
}
</script>

实现Map.vue

<!-- 地图定位组件 -->
<template>
  <div class="map-container">
    <div class="loading" v-if="loading">
      <BaseSpinner spinner="circles"></BaseSpinner>
    </div>
    <div :id="'amap_' + id" class="map-content">
    </div>
  </div>
</template>
<script>
// https://lbs.amap.com/api/webservice/summary
import BaseSpinner from '@/components/base/spinner'
import { generateUUID, loadScript } from '@/assets/js/utils.js'
import amapConf from './amap-conf.js'
export default {
  name: 'AMap',
  components: {
    BaseSpinner
  },
  props: {
    // 位置信息
    value: {
      type: Object
    },
    // 是否可编辑(即更改位置数据)
    editable: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      curValue: this.value && this.value.lat && this.value.lng ? this.value : null,
      id: generateUUID(),
      loading: false
    }
  },
  watch: {
    value (val) {
      this.curValue = val
    }
  },
  mounted () {
    this.showMap()
  },
  methods: {
    showMap () {
      this.loading = true
      this.loadScripts().then((result) => {
        // console.log('############# loadScripts', result)
        result && this.initMap()
      })
    },
    initMap () {
      let map = new window.AMap.Map('amap_' + this.id, {
        resizeEnable: true,
        zoom: 14
      })
      map.on('complete', () => {
        this.loading = false
      })

      if (this.editable) {
        window.AMapUI.loadUI(['misc/PositionPicker', 'misc/PoiPicker'], (PositionPicker, PoiPicker) => {
          let picker = new PositionPicker({
            map,
            mode: 'dragMap'
          })
          picker.on('success', (positionResult) => {
            let value = {
              address: positionResult.address,
              lat: positionResult.position.lat,
              lng: positionResult.position.lng
            }
            this.curValue = value
            this.$emit('changePosition', value)
            this.$emit('input', value)
            // console.log('定位成功: ', positionResult)
          })
          if (this.curValue) {
            // console.log('picker.start([this.curValue.lng, this.curValue.lat])', this.curValue.lng, this.curValue.lat)
            picker.start([this.curValue.lng, this.curValue.lat])
          } else {
            picker.start()
          }
        })
      } else {
        let value = this.curValue // { address: '北京市东城区东华门街道天安门广场', lat: 39.906504, lng: 116.397732 }
        if (value) {
          let position = [this.curValue.lng, this.curValue.lat]
          let marker = new window.AMap.Marker({
            position: position,
            title: value.address
          })
          marker.setMap(map)
          marker.on('click', () => {
            this.$toast({ position: 'top', message: value.address })
          })
          map.setCenter(position)
        }
      }
    },
    // 加载脚本
    loadScripts () {
      return loadScript('http://webapi.amap.com/maps?v=1.4.8&key=' + amapConf.key, 'amap_maps').then(() => {
        return loadScript('http://webapi.amap.com/ui/1.0/main.js?v=1.0.11', 'amap_ui').then(() => {
          return new Promise((resolve, reject) => {
            setTimeout(() => {
              if (!window.AMap) {
                console.error('地图加载失败!')
                resolve(false)
              } else {
                resolve(true)
              }
            }, 100)
          })
        })
      })
    }
  }
}
</script>
<style lang="scss" scoped>
.map-container {
  .map-content {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
  }
  .loading {
    text-align: center;
    height: 300px;
  }
}
</style>

key

/**
 * 高德地图开放接口配置
 * @date 2021/2/2
 */
export default {
  // Web服务API密钥
  key: '1111111'
}

「欢迎在评论区讨论」

希望看完的朋友可以给个赞,鼓励一下