腾讯地图 vue3 使用 封装 地图组件

发布于:2025-07-08 ⋅ 阅读:(17) ⋅ 点赞:(0)

目录

  • map
    • index.ts
    • index.vue

index.ts

// src/utils/loadTMap.ts
declare global {
  interface Window {
    TMap?: any;
  }
}
// 参数名就是腾讯地图的Key
export function loadTMap(key: string): Promise<void> {
  console.log(key,"key")
  return new Promise((resolve, reject) => {
    if (window.TMap) {
      resolve()
      return
    }

    const script = document.createElement('script')
    script.type = 'text/javascript'
    //&libraries=service 这个加上 才可以使用地图的一些方法
    script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${key}&libraries=service`
    script.async = true

    script.onload = () => {
      if (window.TMap) {
        resolve()
      } else {
        reject(new Error('TMap 未正确加载'))
      }
    }

    script.onerror = () => reject(new Error('腾讯地图脚本加载失败'))

    document.head.insertBefore(script, document.head.firstChild)
  })
}

index.vue

<template>
  <div>
    <div id="container" ref="mapContainer"></div>
  </div>
</template>

<script setup lang="ts">
import { ref, defineExpose } from 'vue'
import { loadTMap } from './index' // 你封装的腾讯地图加载器

import { ElMessage } from 'element-plus'

// 类型定义
interface Position {
  lat: number
  lng: number
}

interface GeocoderResultDetail {
  location: Position, //经纬度
  address: string ,//详细地址
  [key: string]: any  //省市区
}

// Props
const props = withDefaults(defineProps<{
  lat?: number
  lon?: number
  mapKey: string,
  region?:string //城市
}>(), {
  lat: 30.570676,
  lon: 104.065173,
  region:"成都市"
})

// Emits
const emit = defineEmits<{
  (e: 'getCoordinates', detail: GeocoderResultDetail): void
}>()

const mapContainer = ref<HTMLElement | null>(null)
const mapInstance = ref<any>(null)
const geocoder = ref<any>(null)
const marker = ref<any>(null)
const resultDetail = ref<GeocoderResultDetail | null>(null)
const hasLoaded = ref(false)
const TMap=ref()
// 初始化地图
const initMap = async () => {
  if (hasLoaded.value) return

  try {
    if (!props.mapKey) return console.warn('地图Key为空')

    await loadTMap(props.mapKey)

    const TMap = window.TMap
    if (!TMap || !mapContainer.value) throw new Error('TMap 加载失败')

    const center = new TMap.LatLng(props.lat, props.lon)

    mapInstance.value = new TMap.Map(mapContainer.value, {
      center,
      zoom: 15
    })

    // 初始化地理编码器
    geocoder.value = new TMap.service.Geocoder()

    // 初始点反查地址
    geocoder.value.getAddress({ location: center })

    // 点击地图获取坐标并反查地址
    mapInstance.value.on('click', (e: any) => {

      const latLng = new TMap.LatLng(e.latLng.lat, e.latLng.lng)
      setMarker(latLng)

      geocoder.value.getAddress({
        location: latLng,
        success: (res: { result: GeocoderResultDetail }) => {
          resultDetail.value = res.result
          console.log("哈哈哈", res.result)
          // emit('getCoordinates', {
          //   location: latLng,
          // })
        },
        fail: (err: any) => {
          console.error('地址解析失败:', err)
        }
      })
    })

    hasLoaded.value = true
  } catch (error) {
    console.error('地图初始化失败:', error)
  }
}

// 打点函数
const setMarker = (latLng: Position) => {

  if (marker.value) marker.value.setMap(null)
const center = new window.TMap.LatLng(latLng.lat, latLng.lng)
  const point = new window.TMap.LatLng(latLng.lat, latLng.lng)
    // 设置地图中心点
  mapInstance.value.setCenter(center)
 try{
   marker.value = new window.TMap.MultiMarker({
    map: mapInstance.value,
    styles: {
    marker: new window.TMap.MarkerStyle({
      width: 25,
      height: 35,
      anchor: { x: 16, y: 32 },
      src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/markerDefault.png'
    })
  },
    geometries:[{
      "id": "1",
        "styleId": 'marker',
        "position": point,
        "properties": {
            "title": "marker4"
        }
    }]
  })

     geocoder.value.getAddress({
        location: point,
      }).then((res:{result:GeocoderResultDetail })=>{
        const {result}=res

        emit('getCoordinates', {
          type: 'getAddress',
          location: {
            lat:result.location.lat,
            lng:result.location.lng
          },
          address: result.address,
          addressInfo: {
            province:result.ad_info.province,
            city:result.ad_info.city,
            district:result.ad_info.district
          }
        })
  });
 }catch(err){
  console.log(err,"家家爱")
 }
}

// 父组件传入地址,地图定位并打点
const setAddress = (address: string) => {
  if (!geocoder.value || !mapInstance.value) return

geocoder.value.getLocation({
        address: address,
      }).then((res:{result:GeocoderResultDetail })=>{
        const {result}=res
setMarker({
  lat:result.location.lat,
  lng: result.location.lng
})
        emit('getCoordinates', {
          type: 'getLocation',
          location: {
            lat:result.location.lat,
            lng:result.location.lng
          },
          address: result.address,
          addressInfo: {
            province:result.ad_info.province,
            city:result.ad_info.city,
            district:result.ad_info.district
          }
        })
      }).catch( (e:any) =>{
        console.log(e)
        ElMessage.error(e.message)

      })

}

// 暴露方法给父组件
defineExpose({
  initMap,
  setAddress,
  getMap: () => mapInstance.value
})
</script>

<style scoped>
#container {
  width: 100%;
  height: 450px;
}
</style>


父组件调用

 <Map :mapKey="defalutKey.txMapKey" ref="tMapRef"  ></Map>
 import Map from "@/components/map/index.vue"
const tMapRef = ref<InstanceType<typeof Map> | null>(null)
// mapKey地图key 
// 中文地址转经纬度,并地图上标点
tMapRef.value?.setAddress(ruleForm.value.mer_address.trim())
tMapRef.value?.initMap()



// 地图更新后, 获取更新后的数据
const getCoordinates = (data: any) => {

ruleForm.value.long=data.location.lng
ruleForm.value.lat=data.location.lat
if(data.type=="getAddress"){
    ruleForm.value.mer_address=data.address
  }else{
    ruleForm.value.province=data.addressInfo.province
    ruleForm.value.city=data.addressInfo.city
    ruleForm.value.district=data.addressInfo.district
  }
}

网站公告

今日签到

点亮在社区的每一天
去签到