Vue基于高德地图API封装一个地图组件

发布于:2024-04-24 ⋅ 阅读:(26) ⋅ 点赞:(0)
一、参考资料
 

高德开放平台 | 高德地图API (amap.com)
 

二、安装及配置
 

pnpm i @vuemap/vue-amap --save

man.ts      密钥及安全密钥需要自己到高德地图开放平台控制台获取.

import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import vant from 'vant'
import 'vant/lib/index.css'
import VueAMap, { initAMapApiLoader } from '@vuemap/vue-amap'
import '@vuemap/vue-amap/dist/style.css'

import * as echarts from 'echarts'

initAMapApiLoader({
  key: '841d5250cb7f61adda2ee70c1e3abdaf',
  securityJsCode: 'd122cbf5a33de34356661cf0cef1a553', // 新版key需要配合安全密钥使用
  plugins: [
    // 定位空间,用来获取和展示用户主机所在的经纬度位置
    'AMap.Geolocation',
    // 输入提示插件
    'AMap.Autocomplete',
    // POI搜索插件
    'AMap.PlaceSearch',
    // 右下角缩略图插件,比例尺
    'AMap.Scale',
    // 地图鹰眼插件
    'AMap.OverView',
    // 地图工具条
    'AMap.ToolBar',
    // 类别切换空间,实现默认图层与卫星图,实施交通层之间切换的控制
    'AMap.MapType',
    // 编辑 折线多边形
    'AMap.PolyEditor',
    'AMap.CircleEditor',
    // 地图编码
    'AMap.Geocoder'
  ]
})

const app = createApp(App)
//全局挂载echarts
app.config.globalProperties.$echarts = echarts
app.use(router)
app.use(ElementPlus)
app.use(VueAMap)
app.use(vant)
app.mount('#app')
三、源码分享
 

1、map.vue

<template>
  <el-dialog v-model="showMapDialog">
    <template #default>
      <div id="container">
        <AmapSelect v-model="locationData" @callback="getMapInfo" />
      </div>
    </template>
  </el-dialog>
</template>

<script lang="ts" setup>
import { ref, nextTick, defineEmits } from 'vue'
// import { ElMessage } from 'element-plus';
import AmapSelect from './AmapSelect.vue'

const props = defineProps({
  title: {
    type: String,
    default: '选择位置'
  },

  center: {
    type: Array,
    default: () => [115.846381, 28.659961]
  }
})

const locationData:any = ref([])
const showMapDialog = ref(false)
const emit = defineEmits(['submit'])

function getMapInfo(info: any) {
  // console.log(info,'info'); 可拿到点击的地址 以及经纬度  可用于做回显等其他操作
  // debugger
  emit('submit', {
    address: info.address,
    lnglat: info.lnglat
  })
}

const openForm = () => {
  showMapDialog.value = true
  nextTick(() => {
    locationData.value=props.center;
  })
}

//提交

// const okModal = async () => {}

//导出方法

defineExpose({
  openForm
})
</script>

<style lang="scss" scoped>
#container {
  height: 400px;
}

.el-dialog__body {
  padding: 0 !important;
}
</style>

2、AmapSelect.vue

<template>
  <el-amap :zoom="zoom" @init="init">
    <el-amap-search-box
      :visible="visible"
      @select="selectChange"
      @choose="handleChange"
      placeholder="请输入"
    />

  </el-amap>
</template>

<script>
export default {
  name: 'AmapSelect',

  emits: ['callback'],

  props: {
    visible: {
      type: Boolean,
      default: true
    },

    modelValue: {
      type: Array,
      default: []
    }
  },

  data() {
    return {
      zoom: 12,
      map: null,
      geocoder: new AMap.Geocoder({}),
      activeAddress: null,
    }
  },

  watch: {
    modelValue: {
      handler(val, oldVal) {
        if (val) {
          // let lnglat = val[1].split(',')

          this.onClickMap({
            lnglat: { lng: val[0], lat: val[1] }
          })
        }
      },

      deep: true
    }
  },

  mounted() {},

  methods: {
    init(map) {
      this.map = map

      map.on('click', this.onClickMap.bind(this))
    },

    selectChange({ poi }) {
      if (poi.location) {
        let { lng, lat } = poi.location

        this.onClickMap(
          {
            lnglat: { lng, lat }
          },

          () => {
            this.map.setCenter([lng, lat])
          }
        )
      }
    },

    handleChange(e) {
      console.log('handleChange: ', e)
    }, 
    
    
    // 点击地图
    onClickMap(e, callback) {
      let lnglat = [e.lnglat.lng, e.lnglat.lat]

      var infoWindow = new AMap.InfoWindow({
        offset: new AMap.Pixel(0, 0)
      })

      this.geocoder.getAddress(lnglat, (status, result) => {
        if (status === 'complete' && result.info === 'OK') {
          // result为对应的地理位置详细信息

          var province = result.regeocode.addressComponent.province //省

          var city = result.regeocode.addressComponent.city //市

          var district = result.regeocode.addressComponent.district //县区

          var township = result.regeocode.addressComponent.township //镇、街道

          var region = province + city + district + township //返回所属区域

          let addressName = result.regeocode.formattedAddress.replace(
            region,
            ''
          )

          let address = ''

          if (!addressName) {
            address = region

            addressName = region
          } else {
            address = result.regeocode.formattedAddress
          }

          let obj = {
            lnglat: lnglat.toString(),

            address: address,

            addressName: addressName
          }

          infoWindow.setContent(this.createdInfoWindowContent(obj))

          infoWindow.open(this.map, lnglat) // 更新数据

          callback && callback()
        }
      })

      this.map.setCenter(lnglat)
    }, 
    // 窗口信息
    createdInfoWindowContent(data) {
      var infoWindowContent =
        '<style>.btn {display: inline-block; font-weight: 400; text-align: center; white-space: nowrap; vertical-align: middle;' +
        '-webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; border: 1px solid transparent;' +
        'transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out;' +
        'background-color: transparent; background-image: none; color: #25A5F7; border-color: #25A5F7; padding: .25rem .5rem; line-height: 1.5;' +
        'border-radius: 1rem;  -webkit-appearance: button; cursor:pointer;}</style>' +
        '<div className="custom-infowindow input-card">' +
        '<label  class="input-item-text">' +
        data.addressName +
        '</label>' +
        '<div class="input-item">' +
        '<div class="input-item-prepend">' +
        '<span style="color:grey">' +
        data.address +
        '</span>' +
        '</div>' +
        '</div>' + // 为 infowindow 添加自定义事件
        '<input id="lnglat2container" type="button" class="btn" value="选择地址" onclick="setLngLat()"/>' +
        '</div>'
        // debugger;

      window.setLngLat = () => {
        this.$emit('update:modelValue', [data.address, data.lnglat])
        this.$emit('callback', data)
      }

      return infoWindowContent
    }
  }
}
</script>

<style lang="scss" scoped>


</style>
四、效果展示

点击窗口信息的选择地址可拿到点击位置的信息然后再做后续操作!!!主要还是参考高德地图API的官方文档.