vue3 TypeScript 腾讯地图关键字输入提示

797 阅读1分钟

一、utils目录下新建utils.ts

/**  加载腾讯地图  */
//txMapKey为腾讯地图申请的mapKey
const txMapKey = 'DZVBZ-J27A6-E4TSU-MZXE4-TUYXH-W5BJI'
let txMapInstance = null

export const loadTxMapPromise: () => Promise<Recordable> = () => {
  return new Promise((resolve, reject) => {
    if (txMapInstance) return resolve(txMapInstance)

    const script = document.createElement('script')
    script.type = 'text/javascript'
    script.src = `https://map.qq.com/api/gljs?v=1.exp&libraries=service&key=${txMapKey}`
    script.onload = function () {
      console.log('腾讯地图加载成功')
      // @ts-ignore
      txMapInstance = window.TMap
      resolve(txMapInstance)
    }
    script.onerror = function () {
      console.log('腾讯地图加载失败')
      reject()
    }
    document.body.appendChild(script)
  })
}

一、新建腾讯地图组件 TencentMaps.vue

<template>
  <div>
    <div id="panel">
      <el-form-item label="" prop="companyName">
        <div class="flex items-center">
          <el-input
            placeholder="请输入关键词"
            clearable
            id="keyword"
            type="text"
            v-model="searchForm.keyword"
            @input="getSuggestions()"
          />
          <el-button id="search" class="ml-[10px]" type="primary" @click="searchByKeyword()">
            搜索
          </el-button>
        </div>
      </el-form-item>

      <ul id="suggestionList" />
    </div>
    <div id="container" />
  </div>
</template>

<script setup lang="ts">
import { onMounted, reactive } from 'vue'
import { loadTxMapPromise } from '/@/utils/utils'

defineOptions({
  name: 'TencentMaps',
})

// 获取父组件传值
const pro = defineProps({
  modelValue: Object,
})

const emit = defineEmits(['update:modelValue', 'active-change'])
const onActiveChange = (value: Recordable) => {
  console.log('value', value)
  emit('active-change', value)
}

const searchForm = reactive({
  keyword: undefined,
})

let map = undefined
let suggestionList = undefined
let search = undefined
let suggest = undefined
let markers = undefined
let infoWindowList = []
let TMap = undefined
let infoWindow = undefined

onMounted(async () => {
  init()
  // vue3+ts使用原生click事件报错
  // 搭建桥梁=>在setup中添加=>window.setSuggestion= setSuggestion;
  window.setSuggestion = setSuggestion
})

//初始化地图
const init = async () => {
  // console.log('modelValue', pro.modelValue)

  TMap = await loadTxMapPromise()
  console.log('TMap', TMap)
  map = new TMap.Map('container', {
    zoom: 14,
    center: new TMap.LatLng(pro.modelValue.lat, pro.modelValue.lng),
  })
  suggestionList = []
  search = new TMap.service.Search({ pageSize: 10 }) // 新建一个地点搜索类
  suggest = new TMap.service.Suggestion({
    // 新建一个关键字输入提示类
    pageSize: 10, // 返回结果每页条目数
    region: pro.modelValue.cityStr || '', // 限制城市范围
    regionFix: true, // 搜索无结果时是否固定在当前城市
  })
  markers = new TMap.MultiMarker({
    map: map,
    geometries: [],
  })
  infoWindowList = Array(10)
}

const getSuggestions = () => {
  // 使用者在搜索框中输入文字时触发
  let suggestionListContainer = document.getElementById('suggestionList')
  suggestionListContainer.innerHTML = ''
  let keyword = searchForm.keyword
  // console.log('keyword', keyword)
  if (keyword) {
    suggest
      .getSuggestions({ keyword: keyword, location: map.getCenter() })
      .then((result) => {
        // console.log('result.data', result.data)
        // 以当前所输入关键字获取输入提示
        suggestionListContainer.innerHTML = ''
        suggestionList = result.data
        suggestionList.forEach((item, index) => {
          suggestionListContainer.innerHTML += `<li onclick="setSuggestion(${index})">${item.title}<span class="item_info">${item.address}</span></li>`
          // suggestionListContainer.innerHTML += `<li><a href="#/merchant/auditingList" onclick="setSuggestion(${index})">${item.title}<span class="item_info">${item.address}</span></a></li>`
        })
      })
      .catch((error) => {
        console.log(error)
      })
  }
}

const setSuggestion = function (index: number) {
  // console.log('index', index)
  if (infoWindowList && infoWindowList.length == 0)
    // 点击输入提示后,于地图中用点标记绘制该地点,并显示信息窗体,包含其名称、地址等信息
    infoWindowList.forEach((infoWindow) => {
      infoWindow.close()
    })
  infoWindowList.length = 0
  searchForm.keyword = suggestionList[index].title
  document.getElementById('suggestionList').innerHTML = ''
  markers.setGeometries([])
  markers.updateGeometries([
    {
      id: '0', // 点标注数据数组
      position: suggestionList[index].location,
    },
  ])
  // console.log('markers', markers)
  infoWindow = new TMap.InfoWindow({
    map: map,
    position: suggestionList[index].location,
    content: `<h3>${suggestionList[index].title}</h3><p>地址:${suggestionList[index].address}</p>`,
    offset: { x: 0, y: -50 },
  })
  infoWindowList.push(infoWindow)
  map.setCenter(suggestionList[index].location)

  markers.on('click', (e) => {
    infoWindowList[Number(e.geometry.id)].open()
    // console.log('infoWindowList[Number(e.geometry.id)]', infoWindowList[Number(e.geometry.id)])
    // 选择经纬度
    onActiveChange(infoWindowList[Number(e.geometry.id)].position)
  })
}

const searchByKeyword = () => {
  // 关键字搜索功能
  infoWindowList.forEach((infoWindow) => {
    infoWindow.close()
  })
  infoWindowList.length = 0
  markers.setGeometries([])
  search
    .searchRectangle({
      keyword: searchForm.keyword,
      bounds: map.getBounds(),
    })
    .then((result) => {
      // console.log('result.data1', result.data)
      result.data.forEach((item, index) => {
        let geometries = markers.getGeometries()
        infoWindow = new TMap.InfoWindow({
          map: map,
          position: item.location,
          content: `
            <h3>${item.title}</h3>
            <p>地址:${item.address}</p>
            <p>电话:${item.tel}</p>
          `,
          offset: { x: 0, y: -50 },
        })
        infoWindow.close()
        infoWindowList[index] = infoWindow
        geometries.push({
          id: String(index),
          position: item.location,
        })
        markers.updateGeometries(geometries)
        markers.on('click', (e) => {
          // console.log(
          //   'infoWindowList[Number(e.geometry.id)]',
          //   infoWindowList[Number(e.geometry.id)]
          // )
          infoWindowList[Number(e.geometry.id)].open()
          // 选择经纬度
          onActiveChange(infoWindowList[Number(e.geometry.id)].position)
        })
      })
    })
}
</script>

<style lang="scss" scoped>
// 腾讯地图
#container {
  width: 100%;
  height: 100%;
}

#panel {
  position: absolute;
  background: #fff;
  width: 350px;
  padding: 20px;
  z-index: 9999;
  top: 30px;
  left: 30px;
}

#suggestionList {
  list-style-type: none;
  padding: 0;
  margin: 0;
}

#suggestionList li a {
  margin-top: -1px;
  background-color: #f6f6f6;
  text-decoration: none;
  font-size: 18px;
  color: black;
  display: block;
}

#suggestionList li .item_info {
  font-size: 12px;
  color: grey;
}

#suggestionList li a:hover:not(.header) {
  background-color: #eee;
}
</style>

三、页面引用

<template>
    <TencentMaps :modelValue="modelValue" @active-change="setLngLat" />
</emplate>

<script setup lang="ts">
const modelValue = ref({
    lng: undefined,
    lat: undefined,
    cityStr: undefined,
  })

//获取腾讯地图组件传值
const setLngLat = (value: Recordable) => {
  console.log('value', value)
}
</sript>

四、知识点

1、ue3+ts使用原生click事件报错

解决: 搭建桥梁=>在setup中添加=>window.setSuggestion= setSuggestion

2、参考:腾讯地图