vue3.0+Tencent map+drag selection+keyword search (Failed to execute 'postMessage' on 'Worker': [object Object] could not be cl)

1. Early stage

1. Obtain the key value from the official website of Tencent Maps, console - application management - create application

 

 2. After the application is successfully created, set the key value

Two, function

1. Introduce the js of Tencent Maps, and add the following statement in the index.html of the public folder of vue

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

 2. Create a map component Map.vue - initialize the map

 <div id="map" />

   Initialize map and center point, monitor map dragging

 Note:  Do not write map and marKerLayer in reactive, ref , otherwise an error will be reported when modifying the center point later

       

       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. Keyword search

<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. Modify the map position

// 修改地图位置
    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. Get the current location and initialize the map

 // 获取当前位置
    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. Reverse parsing address

 // 逆解析地址
    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)
        })
    }

3. Complete code

<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>

Guess you like

Origin blog.csdn.net/sxmzhw/article/details/130742455