腾讯地图组件使用说明文档

概述

本文档介绍如何在vue3+ts的芋道源码后台管理项目中集成和使用腾讯地图组件,包括位置选择、位置查看、静态地图显示等功能。

腾讯地图标记组件的隐藏参数: showDownload: 是否显示下载按钮 (0-否,1-是),此参数为隐藏参数,不在文档里显示,referer设为dianping也会隐藏下载按钮。

环境配置

1. 获取腾讯地图API密钥

  1. 访问 腾讯位置服务控制台

  2. 创建应用并获取API密钥

  3. 在系统配置中设置 tencentLbsKey

2. 域名配置

在小程序或Web应用中,需要将以下域名添加到白名单:

  • apis.map.qq.com

  • lbs.qq.com

基础用法

1. 位置选择组件

用于让用户在地图上选择位置并获取经纬度坐标。

xml 复制代码
<template>

  <el-dialog v-model="mapDialogVisible" title="选择位置" append-to-body>

    <IFrame class="h-609px" :src="locPickerUrl" />

  </el-dialog>

</template>



<script setup>

import * as ConfigApi from '@/api/mall/trade/config'



const mapDialogVisible = ref(false)

const locPickerUrl = ref('')

const selectedLocation = ref({

  latitude: null,

  longitude: null,

  address: ''

})



// 初始化选点组件

const initLocationPicker = async () => {

  const data = await ConfigApi.getTradeConfig()

  const key = data.tencentLbsKey

  locPickerUrl.value = `https://apis.map.qq.com/tools/locpicker?type=1&key=${key}&referer=myapp`

}



// 处理位置选择结果

const selectAddress = (loc) => {

  if (loc.poiname === '我的位置') {

    ElMessage.warning('请移动地图选择位置')

    return

  }



  selectedLocation.value = {

    latitude: loc.latlng?.lat,

    longitude: loc.latlng?.lng,

    address: loc.poiname

  }



  mapDialogVisible.value = false

}



// 监听地图消息

onMounted(() => {

  window.selectAddress = selectAddress

  window.addEventListener('message', (event) => {

    const loc = event.data

    if (loc && loc.module === 'locationPicker') {

      window.parent.selectAddress(loc)

    }

  }, false)



  initLocationPicker()

})

</script>

2. 位置查看组件

用于显示已知位置的标记点。

xml 复制代码
<template>

  <el-dialog v-model="mapDialogVisible" title="查看位置" append-to-body>

    <IFrame class="h-609px" :src="poiMarkerUrl" />

  </el-dialog>

</template>



<script setup>

const props = defineProps({

  latitude: Number,

  longitude: Number,

  title: String,

  address: String

})



const mapDialogVisible = ref(false)

const poiMarkerUrl = ref('')



// 生成标记地图URL

const generatePoiMarkerUrl = async () => {

  if (!props.latitude || !props.longitude) return



  const data = await ConfigApi.getTradeConfig()

  const key = data.tencentLbsKey



  poiMarkerUrl.value = `https://apis.map.qq.com/tools/poimarker?type=0&marker=coord:${props.latitude},${props.longitude};title:${encodeURIComponent(props.title || '位置')};addr:${encodeURIComponent(props.address || '地址')};&key=${key}&referer=myapp`

}



// 打开地图

const openMap = () => {

  if (!props.latitude || !props.longitude) {

    ElMessage.warning('暂无位置信息')

    return

  }

  generatePoiMarkerUrl()

  mapDialogVisible.value = true

}



defineExpose({ openMap })

</script>

3. 静态地图组件

用于显示静态地图图片,无交互功能。

xml 复制代码
<template>

  <div class="static-map">

    <img

      :src="staticMapUrl"

      alt="位置地图"

      class="w-full h-400px object-cover rounded"

      @error="handleMapError"

    />

    <div class="map-info">

      <p><strong>地址:</strong>{{ address }}</p>

      <p><strong>坐标:</strong>{{ longitude }}, {{ latitude }}</p>

    </div>

  </div>

</template>



<script setup>

const props = defineProps({

  latitude: Number,

  longitude: Number,

  address: String

})



const staticMapUrl = ref('')



// 生成静态地图URL

const generateStaticMapUrl = async () => {

  if (!props.latitude || !props.longitude) return



  const data = await ConfigApi.getTradeConfig()

  const key = data.tencentLbsKey



  const markers = `markers=size:large|color:red|${props.latitude},${props.longitude}`

  const center = `center=${props.latitude},${props.longitude}`

  const zoom = 'zoom=16'

  const size = 'size=750x400'

  const format = 'format=png'



  staticMapUrl.value = `https://apis.map.qq.com/ws/staticmap/v2/?${center}&${zoom}&${size}&${markers}&${format}&key=${key}`

}



const handleMapError = () => {

  ElMessage.error('地图加载失败')

}



watch([() => props.latitude, () => props.longitude], () => {

  generateStaticMapUrl()

}, { immediate: true })

</script>



<style scoped>

.map-info {

  margin-top: 16px;

  padding: 16px;

  background-color: #f8f9fa;

  border-radius: 8px;

}



.map-info p {

  margin: 8px 0;

  font-size: 14px;

  color: #606266;

}

</style>

API参考

腾讯地图API端点

1. 选点组件 (LocationPicker)

官网链接:地图组件 | 腾讯位置服务

apis.map.qq.com/tools/locpi...

参数说明:

  • type: 组件类型,1为选点组件

  • key: 腾讯地图API密钥

  • referer: 调用来源标识,可填写任意字符串 (myapp)

  • coord_type: 坐标类型(可选)

  • policy: 显示策略(可选)

​编辑

示例:

bash 复制代码
https://apis.map.qq.com/tools/locpicker?type=1&key=YOUR_KEY&referer=myapp

2. 标记组件 (PoiMarker)

官网链接:地图组件 | 腾讯位置服务

apis.map.qq.com/tools/poima...

参数说明:

  • type: 组件类型,0为标记组件

  • marker: 标记点信息,格式:coord:纬度,经度;title:标题;addr:地址

  • key: 腾讯地图API密钥

  • referer: 调用来源标识,建议为myapp(dianping、meituan、qunhuodong、wexinmp_profile、parking、myapp)

- showDownload: 是否显示下载按钮 (0-否,1-是),此参数为隐藏参数,不在文档里显示,referer设为dianping也会隐藏下载按钮。

如果想隐藏去这里跟查看周边按钮,只需要用白色元素覆盖就行

​编辑

示例:

ini 复制代码
https://apis.map.qq.com/tools/poimarker?type=0&marker=coord:39.908823,116.39747;title:天安门;addr:北京市东城区&key=YOUR_KEY&referer=myapp

3. 静态地图 (StaticMap)

官方文档:WebService API | 腾讯位置服务

apis.map.qq.com/ws/staticma...

参数说明:

  • center: 地图中心点,格式:纬度,经度

  • zoom: 缩放级别,1-18

  • size: 图片尺寸,格式:宽x高

  • markers: 标记点,格式:size:large|color:red|纬度,经度

  • format: 图片格式,png/jpg

  • key: 腾讯地图API密钥

​编辑

示例:

ruby 复制代码
https://apis.map.qq.com/ws/staticmap/v2/?center=39.908823,116.39747&zoom=16&size=750x400&markers=size:large|color:red|39.908823,116.39747&format=png&key=YOUR_KEY

组件示例

完整的位置管理组件

以下是一个完整的位置管理组件示例,包含选择、查看、编辑等功能:

xml 复制代码
<template>

  <div class="location-manager">

    <!-- 位置信息显示 -->

    <el-form-item label="商户位置" prop="address">

      <el-input

        v-model="formData.address"

        :disabled="isDetail"

        placeholder="请输入详细地址"

        class="w-120! mr-2"

      />

      <el-button

        type="primary"

        v-if="!isDetail"

        @click="openLocationPicker"

      >

        获取经纬度

      </el-button>

      <el-button

        type="primary"

        v-else

        @click="openLocationViewer"

        :disabled="!hasLocation"

      >

        查看位置

      </el-button>

    </el-form-item>



    <!-- 经纬度信息显示 -->

    <el-form-item label="经纬度信息" v-if="hasLocation">

      <div class="location-info">

        <div class="location-item">

          <span class="label">经度:</span>

          <span class="value">{{ formData.longitude }}</span>

        </div>

        <div class="location-item">

          <span class="label">纬度:</span>

          <span class="value">{{ formData.latitude }}</span>

        </div>

        <div class="location-actions">

          <el-button type="text" size="small" @click="copyLocation">

            复制坐标

          </el-button>

          <el-button type="text" size="small" @click="openExternalMap">

            外部地图查看

          </el-button>

        </div>

      </div>

    </el-form-item>



    <!-- 地图弹窗 -->

    <el-dialog

      v-model="mapDialogVisible"

      :title="dialogTitle"

      append-to-body

      width="800px"

    >

      <div class="map-wrapper">

        <IFrame class="h-609px" :src="mapUrl" />

        <!-- 按钮遮罩层 -->

        <div class="map-overlay">

          <div class="button-mask bottom-right"></div>

          <div class="button-mask top-right"></div>

          <div class="button-mask bottom-left"></div>

        </div>

      </div>

    </el-dialog>

  </div>

</template>



<script setup>

import * as ConfigApi from '@/api/mall/trade/config'



const props = defineProps({

  modelValue: {

    type: Object,

    default: () => ({

      address: '',

      latitude: null,

      longitude: null

    })

  },

  isDetail: {

    type: Boolean,

    default: false

  },

  title: {

    type: String,

    default: '位置'

  }

})



const emit = defineEmits(['update:modelValue'])



const formData = computed({

  get: () => props.modelValue,

  set: (value) => emit('update:modelValue', value)

})



const mapDialogVisible = ref(false)

const mapUrl = ref('')

const tencentKey = ref('')



// 计算属性

const hasLocation = computed(() =>

  formData.value.latitude && formData.value.longitude

)



const dialogTitle = computed(() =>

  props.isDetail ? '查看位置' : '选择位置'

)



// 初始化腾讯地图配置

const initTencentMap = async () => {

  const data = await ConfigApi.getTradeConfig()

  tencentKey.value = data.tencentLbsKey

}



// 打开位置选择器

const openLocationPicker = async () => {

  mapUrl.value = `https://apis.map.qq.com/tools/locpicker?type=1&key=${tencentKey.value}&referer=myapp`

  mapDialogVisible.value = true

}



// 打开位置查看器

const openLocationViewer = async () => {

  if (!hasLocation.value) {

    ElMessage.warning('暂无位置信息')

    return

  }



  const { latitude, longitude, address } = formData.value

  mapUrl.value = `https://apis.map.qq.com/tools/poimarker?type=0&marker=coord:${latitude},${longitude};title:${encodeURIComponent(props.title)};addr:${encodeURIComponent(address)};&key=${tencentKey.value}&referer=myapp`

  mapDialogVisible.value = true

}



// 处理位置选择结果

const selectAddress = (loc) => {

  if (loc.poiname === '我的位置') {

    ElMessage.warning('请移动地图选择位置')

    return

  }



  formData.value = {

    ...formData.value,

    latitude: loc.latlng?.lat,

    longitude: loc.latlng?.lng,

    address: loc.poiname

  }



  mapDialogVisible.value = false

  ElMessage.success('位置选择成功')

}



// 复制坐标

const copyLocation = async () => {

  const locationText = `${formData.value.longitude},${formData.value.latitude}`

  try {

    await navigator.clipboard.writeText(locationText)

    ElMessage.success('坐标已复制到剪贴板')

  } catch (err) {

    // 降级方案

    const textArea = document.createElement('textarea')

    textArea.value = locationText

    document.body.appendChild(textArea)

    textArea.select()

    document.execCommand('copy')

    document.body.removeChild(textArea)

    ElMessage.success('坐标已复制到剪贴板')

  }

}



// 在外部地图中查看

const openExternalMap = () => {

  const { longitude, latitude, address } = formData.value

  const url = `https://uri.amap.com/marker?position=${longitude},${latitude}&name=${encodeURIComponent(address || props.title)}`

  window.open(url, '_blank')

}



// 初始化

onMounted(() => {

  // 设置全局回调函数

  window.selectAddress = selectAddress



  // 监听地图消息

  window.addEventListener('message', (event) => {

    const loc = event.data

    if (loc && loc.module === 'locationPicker') {

      window.parent.selectAddress(loc)

    }

  }, false)



  initTencentMap()

})

</script>



<style scoped>

.location-info {

  display: flex;

  flex-direction: column;

  gap: 8px;

  padding: 12px;

  background-color: #f8f9fa;

  border-radius: 6px;

  border: 1px solid #e4e7ed;

}



.location-item {

  display: flex;

  align-items: center;

  font-size: 14px;

}



.location-item .label {

  font-weight: 500;

  color: #606266;

  min-width: 50px;

}



.location-item .value {

  color: #303133;

  font-family: 'Courier New', monospace;

  background-color: #fff;

  padding: 2px 6px;

  border-radius: 3px;

  border: 1px solid #dcdfe6;

}



.location-actions {

  display: flex;

  gap: 8px;

  margin-top: 4px;

}



.map-wrapper {

  position: relative;

  width: 100%;

  height: 609px;

  overflow: hidden;

}



.map-overlay {

  position: absolute;

  top: 0;

  left: 0;

  right: 0;

  bottom: 0;

  pointer-events: none;

  z-index: 10;

}



.button-mask {

  position: absolute;

  background-color: rgba(255, 255, 255, 0.9);

  pointer-events: auto;

  border-radius: 4px;

  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);

}



.button-mask.bottom-right {

  bottom: 20px;

  right: 20px;

  width: 80px;

  height: 40px;

}



.button-mask.top-right {

  top: 20px;

  right: 20px;

  width: 120px;

  height: 40px;

}



.button-mask.bottom-left {

  bottom: 20px;

  left: 20px;

  width: 60px;

  height: 40px;

}

</style>

常见问题

1. 地图无法加载

问题描述: 地图组件显示空白或加载失败

解决方案:

  • 检查API密钥是否正确配置

  • 确认域名是否已添加到白名单

  • 检查网络连接是否正常

  • 验证API密钥是否有足够的调用配额

javascript 复制代码
// 检查API密钥配置

const checkApiKey = async () => {

  try {

    const data = await ConfigApi.getTradeConfig()

    if (!data.tencentLbsKey) {

      console.error('腾讯地图API密钥未配置')

      return false

    }

    return true

  } catch (error) {

    console.error('获取API密钥失败:', error)

    return false

  }

}

2. 位置选择回调不触发

问题描述: 用户选择位置后,回调函数没有执行

解决方案:

  • 确保全局回调函数正确设置

  • 检查消息监听器是否正确配置

  • 验证iframe通信是否被浏览器安全策略阻止

javascript 复制代码
// 正确的回调函数设置

onMounted(() => {

  // 设置全局回调函数

  window.selectAddress = selectAddress



  // 监听消息事件

  window.addEventListener('message', (event) => {

    const loc = event.data

    if (loc && loc.module === 'locationPicker') {

      // 确保调用父窗口的回调函数

      if (window.parent && window.parent.selectAddress) {

        window.parent.selectAddress(loc)

      }

    }

  }, false)

})

3. 地图显示位置不准确

问题描述: 地图显示的位置与实际位置不符

解决方案:

  • 检查经纬度数据是否正确

  • 确认坐标系统是否一致(WGS84、GCJ02等)

  • 验证经纬度的顺序是否正确

javascript 复制代码
// 坐标验证函数

const validateCoordinates = (lat, lng) => {

  // 检查纬度范围 (-90 到 90)

  if (lat < -90 || lat > 90) {

    console.error('纬度超出有效范围:', lat)

    return false

  }



  // 检查经度范围 (-180 到 180)

  if (lng < -180 || lng > 180) {

    console.error('经度超出有效范围:', lng)

    return false

  }



  return true

}

4. 按钮遮罩不生效

问题描述: 地图上的"去这里"等按钮仍然可见

解决方案:

  • 调整遮罩层的位置和大小

  • 确保z-index层级正确

  • 检查CSS样式是否被覆盖

css 复制代码
/* 调整遮罩位置 */

.button-mask.bottom-right {

  bottom: 15px;  /* 根据实际按钮位置调整 */

  right: 15px;

  width: 90px;   /* 根据按钮大小调整 */

  height: 45px;

  z-index: 999;  /* 确保层级足够高 */

}

最佳实践

1. 错误处理

始终为地图操作添加错误处理机制:

javascript 复制代码
const handleMapOperation = async () => {

  try {

    // 地图操作代码

    await initTencentMap()

  } catch (error) {

    console.error('地图操作失败:', error)

    ElMessage.error('地图服务暂时不可用,请稍后重试')



    // 提供降级方案

    showManualInput()

  }

}



const showManualInput = () => {

  ElMessageBox.prompt('请手动输入地址', '位置信息', {

    confirmButtonText: '确定',

    cancelButtonText: '取消'

  }).then(({ value }) => {

    formData.value.address = value

  })

}

2. 性能优化

避免频繁的API调用和DOM操作:

javascript 复制代码
// 使用防抖优化地图URL更新

import { debounce } from 'lodash-es'



const updateMapUrl = debounce(async () => {

  // 更新地图URL的逻辑

}, 300)



// 监听数据变化时使用防抖

watch([() => formData.value.latitude, () => formData.value.longitude], () => {

  updateMapUrl()

})

3. 用户体验优化

提供清晰的状态反馈和操作指引:

vbnet 复制代码
const openLocationPicker = async () => {

  // 显示加载状态

  const loading = ElLoading.service({

    lock: true,

    text: '正在加载地图...',

    spinner: 'el-icon-loading'

  })



  try {

    await initMapUrl()

    mapDialogVisible.value = true

  } catch (error) {

    ElMessage.error('地图加载失败')

  } finally {

    loading.close()

  }

}

4. 数据验证

对位置数据进行严格验证:

kotlin 复制代码
const validateLocationData = (data) => {

  const errors = []



  if (!data.address || data.address.trim() === '') {

    errors.push('地址不能为空')

  }



  if (!data.latitude || !data.longitude) {

    errors.push('经纬度信息不完整')

  }



  if (!validateCoordinates(data.latitude, data.longitude)) {

    errors.push('经纬度格式不正确')

  }



  return {

    isValid: errors.length === 0,

    errors

  }

}

5. 安全考虑

保护API密钥和用户数据:

javascript 复制代码
// 不要在前端直接暴露API密钥

// 通过后端接口获取配置信息

const getMapConfig = async () => {

  try {

    const response = await fetch('/api/map/config', {

      headers: {

        'Authorization': `Bearer ${getToken()}`

      }

    })

    return await response.json()

  } catch (error) {

    console.error('获取地图配置失败:', error)

    throw error

  }

}

总结

腾讯地图组件为应用提供了强大的位置服务功能。通过合理的配置和使用,可以为用户提供优秀的位置选择和查看体验。在实际使用中,请注意:

  1. 正确配置API密钥:确保密钥有效且有足够配额

  2. 处理异常情况:提供完善的错误处理和降级方案

  3. 优化用户体验:提供清晰的操作指引和状态反馈

  4. 保护用户隐私:合理使用位置信息,遵守相关法规

  5. 性能优化:避免不必要的API调用和DOM操作

更多详细信息请参考 腾讯位置服务官方文档

相关推荐
前端Hardy3 分钟前
HTML&CSS:超酷炫的3D动态卡片
前端·javascript·css
RaidenLiu31 分钟前
从 Provider 迈向 Riverpod 3:核心架构与迁移指南
前端·flutter
前端进阶者32 分钟前
electron-vite_18Less和Sass共用样式指定
前端
数字人直播34 分钟前
稳了!青否数字人分享3大精细化AI直播搭建方案!
前端·后端
江城开朗的豌豆37 分钟前
我在项目中这样处理useEffect依赖引用类型,同事直呼内行
前端·javascript·react.js
听风的码39 分钟前
Vue2封装Axios
开发语言·前端·javascript·vue.js
转转技术团队40 分钟前
前端安全防御策略
前端
掘金一周1 小时前
被老板逼出来的“表格生成器”:一个前端的自救之路| 掘金一周 8.21
前端·人工智能·后端
cc_z1 小时前
vue代码优化
前端·vue.js
龙在天1 小时前
你只会console.log就Out了
前端