uni-app如何引入天地图并兼容app

项目场景:

uni-app如何引入天地图并兼容appuni-app引入天地图打包成app后,兼容安卓。该方式仅兼容安卓、h5,不支持微信小程序。

安卓模拟器最终效果

image.png
uni-app提供的组件,仅支持下面的服务商,想使用天地图或其他地图,需要搭配地图引擎使用。
image.png

本案例使用工具与插件

  • leaflet.js 轻量的地图引擎,获取无需魔法
  • uni-app
  • HbuilderX 3.8.3
  • MuMu模拟器12 (用于查看实时运行效果)

实现思路

  • uni-app提供的map组件中,仅支持腾讯、百度、高德三个平台的地图,想要切换成天地图需要使用另外的地图渲染引擎来实现。
  • h5端的兼容是最好做的,app与小程序端不支持dom操作,需要另想办法渲染。
  • 地图渲染引擎使用的是 leaflet,相较于其他渲染引擎,它的主体代码比较小。
  • 因为app端不支持dom的操作,使用leaflet 官方提供的渲染方式会出现不渲染情况。这时候需要配合 uni-app 中的renderjs来配合渲染。
  • renderjs 改变了uni-app的渲染模式,在逻辑层之外加上了一个视图层,二者之间互不通信,需要搭配官方提供的通信方式进行通信,同时值得注意的是,二者之间的通信只能是JSON格式的,其他的格式均不支持。

引入步骤

  • 将 leaflet.js 放在 static中,注意路径。如果跟j-leaflet路径不一致,需要改一下。
  • 将 leaflet.css 放在 static中,并引入uni.scss
  • 将 j-leaflet 文件夹放在 components
  • 放置目录结构
    image.png

引用 j-leaflet 组件demo

<template>
	<view>
		<!-- #ifndef MP-WEIXIN -->
		<!-- 除了微信均使用 -->
		<leaflet @changeView="changeView" :location="location" :data="marker"></leaflet>
		<!-- #endif -->
		<!-- #ifdef MP-WEIXIN -->
		<!-- #endif -->
	</view>
</template>
<script>
	import leaflet from '@/components/j-leaflet/j-leaflet.vue'
	export default {
		components: {
			leaflet
		},
		data() {
			var _this = this
			return {
				latitude: 39.909,
				longitude: 116.39742,
				marker:[],
				location:{}
			}
		},
		mounted() {
			setTimeout(()=>{
				this.location = {
					latitude: 39.909,
					longitude: 116.39742,
				}
				this.marker =[this.location]
				
			},2230)
			// this.init()
		},
		methods: {
			changeView(){ 
				console.log(12)
				let list = {
					latitude: 39.901,
					longitude: 116.39712,
				}
				this.marker = [this.location] 
			},
		}
	}
</script>

<style>

</style>

j-leaflet 源码

<template>
	<view :data="data" :change:data="leaflet.addMarker" :location="location" :change:location="leaflet.center"
		class="map" id="map"></view>
</template>
<script>
	export default {
		props: {
			data: Array,
			location: Object 
		},
		methods: {
			changeView(options) {
				this.$emit('changeView', options)
			},
		}
	}
</script>
<script module="leaflet" lang="renderjs">
	import L from 'static/js/leaflet.js';
	export default {
		data() {
			return {
				map: null,
				marker: {}
			};
		},
		mounted() {
			this.initMap()
		},
		methods: {
			// 地图初始化
			initMap() {
				this.map = L.map('map', {
					// crs: L.CRS.EPSG3857,	
					center: [23.180695, 113.412674], 
					zoom: 17, 
					minZoom: 5,
					maxZoom: 18, 
					dragging: true,
					attributionControl: false,
					zoomControl: false
				});
				// 娣诲姞鍥惧眰
				L.tileLayer(
					'http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的秘钥', {
						zoomControl: true
					}).addTo(this.map);
				L.tileLayer(
					'http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的秘钥', {
						zoomControl: true
					}).addTo(this.map);

				this.mapEvent()
			},
			mapEvent() {
				this.map.on('zoomend', (a, b) => {
					let view = this.getBounds()
					// 主动传递 等价于 $emit
					UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
						cid: this._$id,
						method: 'changeView', // 父组件方法
						args: view // 给方法传输的数据
					})
					console.log(24)
				})
				this.map.on('moveend', (a, b) => {
					let view = this.getBounds()
					// 主动传递 等价于 $emit
					UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
						cid: this._$id,
						method: 'changeView',// 父组件方法
						args: view  // 给方法传输的数据
					})
					console.log(25)
				})
			},
			//可视范围 获取
			getBounds() {
				//左下
				let west = this.map.getBounds().getSouthWest()
				var leftdown = [west.lat, west.lng];
				//左上
				let northWest = this.map.getBounds().getNorthWest()
				var leftup = [northWest.lat, northWest.lng];

				//右上
				let orthEast = this.map.getBounds().getNorthEast()
				var rightup = [orthEast.lat, orthEast.lng];
				//右下
				let southEast = this.map.getBounds().getSouthEast()
				var rightdown = [southEast.lat, southEast.lng];
				return {
					leftup,
					leftdown,
					rightup,
					rightdown
				}
			},
			center(point) {
				// 添加中心点,并且移动到地图至中心点
				if (!point || !point.latitude || !point.longitude) return
				if (!this.marker.center) {
					let m = L.marker([point.latitude, point.longitude], {
						icon: L.divIcon({
							className: 'div-icon'
						})
					}).addTo(this.map)
					this.marker.center = m
				} else {
					this.marker.center.setLatLng([point.latitude, point.longitude])
				}
				this.map.panTo({
					lng: point.longitude,
					lat: point.latitude
				});
			},
			addMarker(points) {
				// 获取到数据,进行处理,可以是添加标记,也可以是其他处理
			} 
		}
	}
</script>

<style lang="scss">
	.map {
		width: 100%;
		top: 0;
		bottom: 0;
		position: absolute;
		z-index: 0;
	}
</style>

注意事项

  • 使用leaflet插件对天地图的底图进行渲染,与uni.getLocation 中使用的三方地图的sdk互不相干,是两个独立的东西。
  • 在打不同平台的包时,需要在manifest.json配置不同的地图key。
  • 安卓包需要去对应的地图平台申请安卓使用的key。ios包申请ios使用的 key。
  • 在通信时需要注意对象深浅拷贝问题,最好都是深拷贝,浅拷贝容易发生异常。
  • 云打包每天打包都有固定次数,推荐使用模拟器查看效果。
### 如何在 UniApp 中使用天地图 API #### 创建项目结构配置环境变量 为了确保安全性和灵活性,在 `manifest.json` 文件中的 environment 配置项里设置 TDT_KEY 环境变量来保存申请到的地图 Key。 ```json { "environment": { "TDT_KEY": "your_tdt_key" } } ``` #### 引入必要的资源文件 通过 npm 或者 CDN 的方式引入天地图所需的 JavaScript 库。推荐采用官方提供的最新版本以获得更好的兼容性和支持[^3]。 #### 编写 HTML 结构 定义一个容器用于承载地图展示区域,赋予其特定 ID 方便后续操作: ```html <template> <view class="container"> <!-- 地图容器 --> <view id="mapContainer"></view> <!-- 控制台输出调试信息 --> <text>{{ logMessage }}</text> </view> </template> ``` #### 初始化页面样式 为上述容器设定合适的宽高比例以及基础布局属性,保证地图能够正常渲染呈现给用户查看[^4]: ```css <style scoped> .container { width: 100%; height: calc(100vh - var(--status-bar-height)); } #mapContainer { position: relative; width: 100%; height: 100%; } </style> ``` #### 实现核心逻辑功能 利用 Vue 生命周期钩子 mounted() 方法完成地图初始化工作;同时监听窗口大小变化事件以便自适应调整地图尺寸[^1]。 ```javascript <script> export default { data() { return { mapInstance: null, logMessage: '' }; }, methods: { initMap() { const tdtKey = process.env.TDT_KEY; window._AMapSecurityConfig = { securityJsCode: tdtKey }; this.$nextTick(() => { L.mapquest.key = tdtKey; let mapOptions = { center: [39.904, 116.407], zoom: 12 }; this.mapInstance = L.map('mapContainer', mapOptions); L.tileLayer( 'http://{s}.tianditu.gov.cn/DataServer?T=vec_w&X={x}&Y={y}&L={z}', { attribution: '© <a href="https://www.tianditu.gov.cn">Tianditu</a>', subdomains: ['t0', 't1', 't2', 't3', 't4'] }).addTo(this.mapInstance); console.log('Map initialized successfully.'); this.logMessage = '成功加载'; }); }, handleResize() { if (this.mapInstance !== null && typeof this.mapInstance.invalidateSize === 'function') { this.mapInstance.invalidateSize(); } } }, mounted() { this.initMap(); window.addEventListener('resize', this.handleResize); // 清除不必要的监听器防止内存泄漏 this.$once('hook:beforeDestroy', () => { window.removeEventListener('resize', this.handleResize); if (typeof this.mapInstance?.remove === 'function') { this.mapInstance.remove(); } }); } }; </script> ```
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值