vue3.0+腾讯地图+拖拽选择+关键字搜索(Failed to execute ‘postMessage‘ on ‘Worker‘: [object Object] could not be cl)

该文章详细介绍了如何在Vue项目中集成腾讯地图API,包括创建应用获取key值、初始化地图、设置地图中心点、监听地图移动、关键字搜索、选择地址、修改地图位置以及获取当前位置和逆解析地址的步骤。同时,提供了完整的代码示例,展示了一个包含地址输入框和地图的对话框组件。
摘要由CSDN通过智能技术生成

一、前期

1、腾讯地图官网获取key值 ,控制台——应用管理——创建应用

 

 2、创建应用成功后设置key值

二、功能

1、引入腾讯地图的js,在vue的public文件夹的index.html中加上以下语句

 <script charset="utf-8" src="https://map.qq.com/api/gljs?v=1.exp&key=在官网控制台获取的key"></script>

 2、创建地图组件Map.vue——初始化地图

 <div id="map" />

   初始化地图和中心点 ,监控地图拖动

 注: mapmarKerLayer不要写在reactive,ref中否则在之后修改中心点时会报错

       

       Failed to execute ‘postMessage‘ on ‘Worker‘: [object Object] could not be cloned

 var map = null // 地图
 var markerLayer = null// 点标记
// 初始化地图/定位
    const getinitChange = (lat, lng) => {
      console.log(lat, lng)
      // 定义地图中心点坐标
      const myLatlng = new window.TMap.LatLng(lat, lng)
      vueConfig.lat = lat
      vueConfig.lng = lng
      // 定义map变量,调用 window.TMap.Map() 构造函数创建地图
      map = new window.TMap.Map(document.getElementById('map'), {
        center: myLatlng, // 设置地图中心点坐标
        zoom: 17.2 // 设置地图缩放级别
      })
      var geometries = {
        id: '1', // 点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
        styleId: 'myStyle', // 指定样式id
        position: myLatlng // 点标记坐标位置
      }
      markerLayer = new window.TMap.MultiMarker({
        map: map,
        styles: {
          // 创建一个styleId为"myStyle"的样式(styles的子属性名即为styleId)
          myStyle: new window.TMap.MarkerStyle({
            width: 25, // 点标记样式宽度(像素)
            height: 30 // 点标记样式高度(像素)
          })
        },
        // 点标记数据数组
        geometries: [geometries]
      })
      // 监听地图正在平移的状态
      map.on('pan', function() {
        markerLayer.updateGeometries([
          {
            'styleId': 'myStyle',
            'id': '1',
            'position': map.getCenter()
          }
        ])
      })
      // 监听地图结束平移
      map.on('panend', function() { // 拖拽结束时获取地址
        getInverseAnalysis()
      })
    }

3、关键字搜索

<el-autocomplete
        v-model="vueConfig.address"
        value-key="title"
        :fetch-suggestions="querySearch"
        :trigger-on-focus="false"
        @select="handleSelect"
      >
        <template #append>
          <el-button icon="el-icon-search" />
        </template>
</el-autocomplete>
 // 关键字查询
    const querySearch = (queryString, callback) => {
      const url = 'https://apis.map.qq.com/ws/place/v1/suggestion' // 关键字查询
      jsonp(url, {
        key: vueConfig.key,
        keyword: queryString,
        output: 'jsonp'
      })
        .then(res => {
          if (res.status == 0) {
            const list = res.data
            callback(list)
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
    }

 // 选择地址
    const handleSelect = (item) => {
      vueConfig.lat = item.location.lat
      vueConfig.lng = item.location.lng
      vueConfig.location = item
      vueConfig.ispan = false
      setInitChange()
    }

4、修改地图位置

// 修改地图位置
    const setInitChange = () => {
      map.setCenter(new window.TMap.LatLng(vueConfig.lat, vueConfig.lng))
      markerLayer.updateGeometries([
        {
          'styleId': 'myStyle',
          'id': '1',
          'position': new window.TMap.LatLng(vueConfig.lat, vueConfig.lng)
        }
      ])
    }

5、获取当前位置,初始化地图

 // 获取当前位置
    const getNowLngAndLat = () => {
      const url = 'https://apis.map.qq.com/ws/location/v1/ip'
      jsonp(url, {
        key: vueConfig.key,
        output: 'jsonp'
      })
        .then(res => {
          if (res.status == 0) {
            vueConfig.lat = res.result.location.lat
            vueConfig.lng = res.result.location.lng
            getinitChange(vueConfig.lat, vueConfig.lng)
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
    }

6、逆解析地址

 // 逆解析地址
    const getInverseAnalysis = () => {
      const location = `${map.getCenter().lat},${map.getCenter().lng}`
      const url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='
      jsonp(url, {
        location: location,
        output: 'jsonp',
        key: vueConfig.key
      })
        .then(res => {
          if (res.status == 0) {
            if (vueConfig.ispan) {
              vueConfig.lat = res.result.location.lat
              vueConfig.address = res.result.formatted_addresses.recommend
              vueConfig.lng = res.result.location.lng
            }
            vueConfig.ispan = true
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
        .catch(err => {
          console.log(err)
        })
    }

三、 完整代码

<template>
  <el-dialog
    v-model="vueConfig.dialogAddressVisible"
    title="获取经纬度"
    :close-on-click-modal="false"
    :destroy-on-close="true"
    :append-to-body="true"
    width="55%"
    @close="handleClose()"
  >
    <div class="map-input">
      <el-autocomplete
        v-model="vueConfig.address"
        value-key="title"
        :fetch-suggestions="querySearch"
        :trigger-on-focus="false"
        @select="handleSelect"
      >
        <template #append>
          <el-button icon="el-icon-search" />
        </template>
      </el-autocomplete>

    </div>
    <div id="map" />
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleClose()">取消</el-button>
        <el-button type="primary" @click="confirmMap">确认地址</el-button>
      </span>
    </template>
  </el-dialog>
</template>
<script >
import { reactive, nextTick, watch } from 'vue'
import { jsonp } from 'vue-jsonp'
import { ElMessage } from 'element-plus'

export default {
  props: {
    lat: {
      type: Number,
      default: 0
    },
    lng: {
      type: Number,
      default: 0
    },
    address: {
      type: String,
      default: ''
    },
    dialogVisible: {
      type: Boolean,
      default: false
    }
  },
  emits: ['sure', 'change'],

  setup(props, ctx) {
    var map = null // 地图
    var markerLayer = null// 点标记
    const vueConfig = reactive({
      dialogAddressVisible: false,
      address: '', // 地址
      lat: 0,
      lng: 0,
      key: '你申请的key值',
      ispan: false,
      location: {}// 地址详情
    })

   

    watch(
      () => props.dialogVisible,
      () => {
        vueConfig.dialogAddressVisible = props.dialogVisible
        vueConfig.address = props.address
        vueConfig.lat = props.lat
        vueConfig.lng = props.lng
        nextTick(() => {
          if (vueConfig.dialogAddressVisible) {
            if (!props.lat) {
              getNowLngAndLat() //根据ip获取当前位置
            } else {
              getinitChange(props.lat, props.lng)//初始化地图
            }
          }
        })
      },
      { immediate: true }
    )

    // 关键字查询
    const querySearch = (queryString, callback) => {
      const url = 'https://apis.map.qq.com/ws/place/v1/suggestion' // 关键字查询
      jsonp(url, {
        key: vueConfig.key,
        keyword: queryString,
        output: 'jsonp'
      })
        .then(res => {
          if (res.status == 0) {
            const list = res.data
            callback(list)
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
    }
    // 选择地址
    const handleSelect = (item) => {
      vueConfig.lat = item.location.lat
      vueConfig.lng = item.location.lng
      vueConfig.location = item
      vueConfig.ispan = false
      setInitChange()
    }
    // 修改地图位置
    const setInitChange = () => {
      map.setCenter(new window.TMap.LatLng(vueConfig.lat, vueConfig.lng))
      markerLayer.updateGeometries([
        {
          'styleId': 'myStyle',
          'id': '1',
          'position': new window.TMap.LatLng(vueConfig.lat, vueConfig.lng)
        }
      ])
    }

    // 获取当前位置
    const getNowLngAndLat = () => {
      const url = 'https://apis.map.qq.com/ws/location/v1/ip'
      jsonp(url, {
        key: vueConfig.key,
        output: 'jsonp'
      })
        .then(res => {
          if (res.status == 0) {
            vueConfig.lat = res.result.location.lat
            vueConfig.lng = res.result.location.lng
            getinitChange(vueConfig.lat, vueConfig.lng)
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
    }

    // 逆解析地址
    const getInverseAnalysis = () => {
      const location = `${map.getCenter().lat},${map.getCenter().lng}`
      const url = 'https://apis.map.qq.com/ws/geocoder/v1/?location='
      jsonp(url, {
        location: location,
        output: 'jsonp',
        key: vueConfig.key
      })
        .then(res => {
          if (res.status == 0) {
            if (vueConfig.ispan) {
              vueConfig.lat = res.result.location.lat
              vueConfig.address = res.result.formatted_addresses.recommend
              vueConfig.lng = res.result.location.lng
            }
            vueConfig.ispan = true
          } else {
            ElMessage({
              type: 'error',
              message: res.message
            })
          }
        })
        .catch(err => {
          console.log(err)
        })
    }
    // 初始化地图/定位
    const getinitChange = (lat, lng) => {
      console.log(lat, lng)
      // 定义地图中心点坐标
      const myLatlng = new window.TMap.LatLng(lat, lng)
      vueConfig.lat = lat
      vueConfig.lng = lng
      // 定义map变量,调用 window.TMap.Map() 构造函数创建地图
      map = new window.TMap.Map(document.getElementById('map'), {
        center: myLatlng, // 设置地图中心点坐标
        zoom: 17.2 // 设置地图缩放级别
      })
      var geometries = {
        id: '1', // 点标记唯一标识,后续如果有删除、修改位置等操作,都需要此id
        styleId: 'myStyle', // 指定样式id
        position: myLatlng // 点标记坐标位置
      }
      markerLayer = new window.TMap.MultiMarker({
        map: map,
        styles: {
          // 创建一个styleId为"myStyle"的样式(styles的子属性名即为styleId)
          myStyle: new window.TMap.MarkerStyle({
            width: 25, // 点标记样式宽度(像素)
            height: 30 // 点标记样式高度(像素)
          })
        },
        // 点标记数据数组
        geometries: [geometries]
      })
      // 监听地图正在平移的状态
      map.on('pan', function() {
        markerLayer.updateGeometries([
          {
            'styleId': 'myStyle',
            'id': '1',
            'position': map.getCenter()
          }
        ])
      })
      // 监听地图结束平移
      map.on('panend', function() { // 拖拽结束时获取地址
        getInverseAnalysis()
      })
    }
    const resetFormData = () => { //清空地图
      map = null
      markerLayer = null
    }

    const handleClose = () => { //关闭
      resetFormData()
      ctx.emit('change', null)
    }

    const confirmMap = () => {//确认地址
      const location = {
        lat: vueConfig.lat,
        lng: vueConfig.lng,
        address: vueConfig.address
      }
      if (!vueConfig.address) {
        ElMessage({
          type: 'warning',
          message: '请获取地址/经纬度'
        })
        return false
      }

      ctx.emit('sure', location)
    }

    return {
      vueConfig,
      getinitChange,
      handleSelect,
      querySearch,
      setInitChange,
      map,
      markerLayer,
      confirmMap,
      getInverseAnalysis,
      handleClose,
      resetFormData
    }
  }
}
</script>

  <style lang="scss" scoped>
  .map-input {
    margin-bottom: 20px;
    display: flex;

    :deep(.el-autocomplete) {
      width: 100%;
    }
  }

  .map {
    position: relative;
  }

  .biadian {
    position: absolute;
    top: calc(50% - 25px);
    left: 50%;
    transform: translate(-50%, -50%);
    width: 50px;
    height: 50px;
  }
  </style>

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值