当前位置: 首页 > article >正文

腾讯位置服务点标记

效果:

1、子组件

<template>
	<div class="tengxunMapMarker" :style="{ height: `${height}px` }">
		<div :id="`container-${mid}`" class="xn-wh"></div>
	</div>
</template>

<script setup name="tengxunMapMarker">
import { onMounted, onUnmounted, ref, shallowRef } from 'vue'

const props = defineProps({
	mid: {
		type: Number,
		default: new Date().getTime()
	},
	height: {
		type: Number,
		default: 800
	},
	apiKey: {
		type: String,
		required: true
	},
	center: {
		type: Array
	},
	zoom: {
		type: Number,
		default: 12
	},
	mapStyle: {
		type: String,
		default: '1', // 默认普通样式
		validator(value) {
			return ['1', '2', '3', '4'].includes(value) // 1:普通 2:夜景 3:卫星 4:混合
		}
	},
	markerCluster: {
		type: Boolean,
		default: true
	}
})

const emits = defineEmits(['complete', 'markerClick'])

const map = shallowRef(null)
const markers = ref([])
const infoWindows = ref({})

// 初始化地图
const initMap = () => {
	// 确保腾讯地图JS API已加载
	if (!window.TMap) {
		const script = document.createElement('script')
		script.type = 'text/javascript'
		script.src = `https://map.qq.com/api/gljs?v=1.exp&key=${props.apiKey}`
		script.onload = () => {
			createMap()
		}
		document.head.appendChild(script)
	} else {
		createMap()
	}
}

// 创建地图实例
const createMap = () => {
	// console.log('center....', props.center)
	map.value = new TMap.Map(document.getElementById(`container-${props.mid}`), {
		zoom: props.zoom,
		mapStyleId: props.mapStyle
	})
	if (props.center) {
		map.value.setCenter(props.center)
	}

	// 添加地图点击事件监听
	map.value.on('click', (evt) => {
		emits('markerClick', {
			lnglat: {
				lng: evt.latLng.lng,
				lat: evt.latLng.lat
			}
		})
	})

	map.value.on('tilesloaded', () => {
		emits('complete')
	})
}

// 添加标记点
const renderMarker = (dataArr) => {
	clearOverlay()

	const markerLayer = new TMap.MultiMarker({
		map: map.value,
		styles: {
			default: new TMap.MarkerStyle({
				width: 25,
				height: 35,
				anchor: {x: 12.5, y: 35},
			})
		},
		geometries: dataArr.map((item) => {
			return {
				id: item.id || String(Math.random()),
				position: new TMap.LatLng(item.position[1], item.position[0]), // 纬度在前,经度在后
				properties: {
					title: item.title || ''
				}
			}
		})
	})

	// console.log('Marker layer created:', markerLayer)
	markers.value.push(markerLayer)
}

// 添加信息窗体
const renderInfoWindow = (dataArr) => {
	dataArr.forEach((item) => {
		const position = new TMap.LatLng(item.position[0], item.position[1])
		const info = new TMap.InfoWindow({
			map: map.value,
			position,
			content: item.content.join('<br>'),
			offset: {x: 0, y: -32}
		})
		infoWindows.value[item.position.join(',')] = info
		info.close() // 默认关闭
	})
}

// 打开信息窗体
const openInfoWindow = (position) => {
	const key = position.join(',')
	if (infoWindows.value[key]) {
		infoWindows.value[key].open()
	}
}

// 清除覆盖物
const clearOverlay = () => {
	markers.value.forEach((marker) => {
		marker.setMap(null)
	})
	markers.value = []

	Object.values(infoWindows.value).forEach((info) => {
		info.setMap(null)
	})
	infoWindows.value = {}
}

// 绘制线段
const renderPolyline = (dataArr, option = {}) => {
	const polylineLayer = new TMap.MultiPolyline({
		map: map.value,
		styles: {
			style_blue: new TMap.PolylineStyle({
				color: option.strokeColor || '#3777FF',
				width: option.strokeWeight || 2,
				borderWidth: option.borderWeight || 1,
				opacity: option.strokeOpacity || 0.5
			})
		},
		geometries: [
			{
				styleId: 'style_blue',
				paths: dataArr.map((item) => new TMap.LatLng(item.position[0], item.position[1]))
			}
		]
	})
	markers.value.push(polylineLayer)
}

// 绘制圆形
const renderCircle = (position, radius, option = {}) => {
	const circleLayer = new TMap.MultiCircle({
		map: map.value,
		styles: {
			circle: new TMap.CircleStyle({
				color: option.fillColor || '#3777FF',
				fillColor: option.fillColor || '#3777FF',
				fillOpacity: option.fillOpacity || 0.5,
				strokeColor: option.strokeColor || '#3777FF',
				strokeWidth: option.strokeWeight || 2,
				strokeOpacity: option.strokeOpacity || 0.5
			})
		},
		geometries: [
			{
				center: new TMap.LatLng(position[0], position[1]),
				radius: radius
			}
		]
	})
	markers.value.push(circleLayer)
}

// 暴露获取地址的方法
const getAddress = async (lnglat) => {
	return new Promise((resolve) => {
		geocoder.getAddress(lnglat, (status, result) => {
			if (status === 'complete' && result.info === 'OK') {
				resolve(result.regeocode.formattedAddress)
			} else {
				resolve(null)
			}
		})
	})
}

onMounted(() => {
	setTimeout(() => {
		initMap()
	}, 100)
})

onUnmounted(() => {
	if (map.value) {
		map.value.destroy()
	}
})

defineExpose({
	renderMarker,
	renderInfoWindow,
	openInfoWindow,
	clearOverlay,
	renderPolyline,
	renderCircle,
	getAddress
})
</script>

<style lang="less">
.tengxunMapMarker {
	position: relative;
	overflow: hidden;

	.xn-wh {
		width: 100%;
		height: 100%;
		min-height: 300px;
	}
}
</style>

2、父组件

<a-form-item>
	<a-alert message="点击地图,快速选择地点" type="warning" closable/>
		<TengxunMapMarker
			:zoom="17"
			:height="300"
			:apiKey="props.apiKey"
			 @markerClick="onMapClick"
			 @complete="onMapComplete"
			 :center="mapCenter"
			 :pitch="30"
			 ref="tengxunMapRef"
				/>
			</a-form-item>


const mapCenter = computed(() => ({
		lat: Number(latitude.value),
		lng: Number(longitude.value)
	}))


// 处理第一个地图的点击事件(选择中心点)
	const onMapClick = (e) => {
		// 更新表单数据
		lng = e.lnglat.lng.toFixed(6)
		lat = e.lnglat.lat.toFixed(6)

		// 更新地图中心点
		latitude.value = Number(e.lnglat.lat)
		longitude.value = Number(e.lnglat.lng)

		tengxunMapRef.value.renderMarker([
			{
				id: 'current',
				position: [longitude.value, latitude.value], // 经度在前,纬度在后
				title: '当前位置'
			}
		])
	}


const onMapComplete = () => {
		if (formData.value.id) {
			latitude.value = Number(formData.value.lat)
			longitude.value = Number(formData.value.lng)
			tengxunMapRef.value.renderMarker([
				{
					id: formData.value.id,
					position: [formData.value.lng, formData.value.lat], // 经度在前,纬度在后
					title: formData.value.name || '标注点'
				}
			])
		}
	}


http://www.kler.cn/a/595365.html

相关文章:

  • 【jQuery】常用API
  • idea中ctrl + shift +f失效的问题
  • LeetCode热题100JS(59/100)第十一天|46|78|17|39|22
  • Linux驱动开发-①中断②阻塞、非阻塞IO和异步通知
  • Python 爬取 1688 商品详情接口数据全攻略
  • iStoreOS软路由对硬盘格式化分区(转化ext4)
  • Java实现十大经典排序算法详解
  • Linux--软硬链接、动静态库
  • 内核ICMP协议分析
  • 使用excel.EasyExcel实现导出有自定义样式模板的excel数据文件,粘贴即用!!!
  • C# 项目06-计算程序运行时间
  • mysql 对json的处理?
  • deepseek使用记录25——当反思失效了
  • AI工具如何改变编程学习?Trae IDE与Claude 3.5的实践案例
  • 使用AI一步一步实现若依(18)
  • SpringBoot整合MQTT最详细版(亲测有效)
  • 基于springboot的教师工作量管理系统(031)
  • 同旺科技USB to I2C 适配器 ---- 指令循环发送功能
  • Linux系统——keepalived安装与部署
  • Eplan许可分析