news 2026/4/17 10:38:18

Vue3项目里用天地图API做个地图功能,从配置到覆盖物完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Vue3项目里用天地图API做个地图功能,从配置到覆盖物完整流程

Vue3实战:从零构建天地图可视化组件全流程指南

在数据驱动的现代Web应用中,地图功能已成为管理后台和数据大屏的核心组件。作为国内领先的地理信息服务,天地图凭借其稳定的服务和丰富的地图数据,成为众多企业的首选。本文将带您从零开始,在Vue3项目中完整实现一个具备标记点、信息窗口等高级功能的天地图组件,并分享TypeScript深度集成和性能优化的实战经验。

1. 环境准备与基础配置

天地图服务的接入始于开发者账号的申请。访问天地图开放平台,完成个人或企业认证后,进入"控制台→应用管理"创建新应用。这里需要特别注意:

  • 服务类型:选择"浏览器端"(JS API)
  • 白名单配置:建议设置为*允许所有域名(正式环境请替换为具体域名)
  • 配额管理:免费版每日调用限额为10万次,超出需购买商用套餐

获取到API Key后,我们有两种引入方式可选:

<!-- 方式一:传统script标签引入 --> <script src="http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥"></script> <!-- 方式二:动态加载(推荐) --> <script> function loadTianDiTuAPI() { return new Promise((resolve) => { if (window.T) return resolve(true) const script = document.createElement('script') script.src = `http://api.tianditu.gov.cn/api?v=4.0&tk=您的密钥` script.onload = () => resolve(true) document.head.appendChild(script) }) } </script>

对于Vue3项目,推荐采用动态加载方案,它具备以下优势:

  1. 避免阻塞主线程,提升页面加载性能
  2. 实现按需加载,减少初始包体积
  3. 便于错误处理和重试机制实现

2. 核心地图组件的构建

2.1 组件基础结构

使用Vue3的Composition API创建基础组件框架:

<template> <div class="tmap-container"> <div ref="mapEl" class="tmap-viewport"></div> <slot></slot> </div> </template> <script lang="ts" setup> import { ref, onMounted, onBeforeUnmount, watch } from 'vue' const props = defineProps({ center: { type: Array as () => [number, number], default: () => [116.404, 39.915] }, zoom: { type: Number, default: 12 }, mapType: { type: String, default: 'normal' } // normal/terrain/satellite }) const mapEl = ref<HTMLElement | null>(null) let mapInstance: any = null onMounted(async () => { await initMap() }) onBeforeUnmount(() => { destroyMap() }) </script> <style scoped> .tmap-container { position: relative; width: 100%; height: 100%; } .tmap-viewport { width: 100%; height: 100%; background: #f0f2f5; } </style>

2.2 地图初始化与响应式控制

天地图API的初始化需要特别注意坐标系的选择。国内常用的坐标系包括:

坐标系类型标识符适用场景
经纬度坐标EPSG:4326国际标准,兼容GPS设备
墨卡托投影EPSG:3857网络地图通用,显示更精确
// 在setup函数中继续编写 const initMap = async () => { await loadTianDiTuAPI() if (!mapEl.value) return const T = window.T mapInstance = new T.Map(mapEl.value, { projection: 'EPSG:3857' // 推荐使用墨卡托投影 }) // 设置初始视图 mapInstance.centerAndZoom( new T.LngLat(...props.center), props.zoom ) // 设置地图类型 const typeMap = { normal: TMAP_NORMAL_MAP, terrain: TMAP_TERRAIN_MAP, satellite: TMAP_HYBRID_MAP } mapInstance.setMapType(typeMap[props.mapType]) // 添加基本控件 mapInstance.addControl(new T.Control.Zoom()) mapInstance.addControl(new T.Control.OverviewMap()) } // 响应式更新处理 watch(() => props.center, (newVal) => { if (mapInstance && newVal) { mapInstance.setCenter(new T.LngLat(...newVal)) } }) watch(() => props.zoom, (newVal) => { if (mapInstance && newVal) { mapInstance.setZoom(newVal) } })

3. 高级覆盖物实现技巧

3.1 标记点与信息窗口

天地图提供多种标记点样式,我们还可以自定义图标:

const addMarker = (lnglat: [number, number], options = {}) => { if (!mapInstance) return null const T = window.T const defaultIcon = new T.Icon({ iconUrl: '//api.tianditu.gov.cn/img/markers/marker_red.png', iconSize: new T.Point(25, 35), iconAnchor: new T.Point(12, 35) }) const marker = new T.Marker( new T.LngLat(...lnglat), { icon: options.icon || defaultIcon } ) mapInstance.addOverLay(marker) // 信息窗口实现 if (options.content) { const infoWindow = new T.InfoWindow({ content: options.content, position: new T.LngLat(...lnglat) }) marker.addEventListener('click', () => { infoWindow.open(mapInstance) }) } return marker }

3.2 折线与多边形绘制

对于路径规划或区域标注需求,可以使用以下方法:

const addPolyline = (points: Array<[number, number]>, style = {}) => { if (!mapInstance || points.length < 2) return null const T = window.T const line = new T.Polyline( points.map(p => new T.LngLat(...p)), { color: '#3388ff', weight: 3, opacity: 0.8, ...style } ) mapInstance.addOverLay(line) return line } const addPolygon = (points: Array<[number, number]>, style = {}) => { if (!mapInstance || points.length < 3) return null const T = window.T const polygon = new T.Polygon( points.map(p => new T.LngLat(...p)), { color: '#3388ff', weight: 2, opacity: 0.6, fillColor: '#3388ff', fillOpacity: 0.3, ...style } ) mapInstance.addOverLay(polygon) return polygon }

4. 性能优化与最佳实践

4.1 大数据量渲染优化

当地图需要展示大量标记点时(如门店分布、设备点位),直接渲染会导致性能急剧下降。可采用以下策略:

  1. 聚合显示:使用标记点聚类插件

    const initCluster = (points: Array<[number, number, any]>) => { const T = window.T const markers = points.map(p => { const marker = new T.Marker(new T.LngLat(p[0], p[1])) marker.data = p[2] // 附加数据 return marker }) const cluster = new T.MarkerClusterer(mapInstance, { gridSize: 80, maxZoom: 15, styles: [{ url: '//api.tianditu.gov.cn/img/markers/marker_blue.png', size: new T.Point(30, 40), textColor: '#fff', textSize: 12 }] }) cluster.addMarkers(markers) return cluster }
  2. 视图区域筛选:只渲染当前视野范围内的标记点

    const setupViewportFilter = () => { if (!mapInstance) return const updateVisibleMarkers = () => { const bounds = mapInstance.getBounds() allMarkers.forEach(marker => { const visible = bounds.contains(marker.getPosition()) marker[visible ? 'show' : 'hide']() }) } mapInstance.addEventListener('moveend', updateVisibleMarkers) mapInstance.addEventListener('zoomend', updateVisibleMarkers) }

4.2 内存管理与事件清理

Vue组件卸载时务必清理地图资源和事件监听,避免内存泄漏:

const destroyMap = () => { if (!mapInstance) return // 移除所有覆盖物 mapInstance.clearOverLays() // 移除所有事件监听 mapInstance.removeEventListener('click') mapInstance.removeEventListener('moveend') // 销毁地图实例 mapInstance.destroy() mapInstance = null }

5. 组件封装与业务集成

5.1 可复用组件设计

将地图功能封装为业务组件时,建议采用以下设计模式:

<template> <TianDiTuMap :center="mapCenter" :zoom="zoomLevel" @marker-click="handleMarkerClick" > <template #controls> <MapToolbar @search="handleSearch" /> </template> </TianDiTuMap> </template> <script setup> // 业务逻辑处理 const handleMarkerClick = (marker) => { fetchDetailData(marker.id).then(data => { showInfoWindow(data) }) } </script>

5.2 TypeScript深度集成

为天地图API创建类型声明文件tianditu.d.ts

declare namespace TMap { class Map { constructor(container: HTMLElement, options?: MapOptions) setCenter(lnglat: LngLat): void setZoom(zoom: number): void addOverLay(overlay: Overlay): void // 其他方法声明... } interface LngLat { lng: number lat: number } // 其他类型声明... } declare const T: typeof TMap

在组件中使用时获得完整的类型提示:

let mapInstance: TMap.Map | null = null const initMap = () => { mapInstance = new T.Map(mapEl.value!, { projection: 'EPSG:3857' }) // 现在可以获得完整的类型检查 }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/17 10:35:14

GOOSE报文深度解析:从ASN.1结构到网络抓包实践

1. GOOSE报文基础与IEC61850标准 GOOSE&#xff08;Generic Object Oriented Substation Event&#xff09;是变电站自动化系统中的关键通信机制&#xff0c;属于IEC61850标准中定义的GSE&#xff08;Generic Substation Event&#xff09;模型的一部分。我第一次接触GOOSE报文…

作者头像 李华
网站建设 2026/4/17 10:35:13

显卡驱动彻底清理解决方案:Display Driver Uninstaller 技术指南

显卡驱动彻底清理解决方案&#xff1a;Display Driver Uninstaller 技术指南 【免费下载链接】display-drivers-uninstaller Display Driver Uninstaller (DDU) a driver removal utility / cleaner utility 项目地址: https://gitcode.com/gh_mirrors/di/display-drivers-un…

作者头像 李华
网站建设 2026/4/17 10:34:13

专业级M4S转MP4工具深度解析:B站视频缓存格式转换技术揭秘

专业级M4S转MP4工具深度解析&#xff1a;B站视频缓存格式转换技术揭秘 【免费下载链接】m4s-converter 一个跨平台小工具&#xff0c;将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter m4s-converter是一款专为B…

作者头像 李华
网站建设 2026/4/17 10:31:35

intv_ai_mk11多场景:从学生作业辅导到程序员代码注释生成的真实用例

intv_ai_mk11多场景&#xff1a;从学生作业辅导到程序员代码注释生成的真实用例 1. 模型介绍与核心能力 intv_ai_mk11是一个基于Llama架构的中等规模文本生成模型&#xff0c;特别适合处理日常问答、文本改写、解释说明等任务。这个模型最大的特点是开箱即用——不需要复杂的…

作者头像 李华