uniapp中引入Leaflet

发布时间 2023-11-10 01:59:46作者: 当时明月在曾照彩云归

1. 引言

uniapp中自带有map组件,并且自带的map组件有常见的显示地图、绘制点线面的功能

但是,它存在以下问题:

  • 收费,自带的map组件使用的是高德、腾讯的地图,无论使用什么样的功能,即使只是绘制底图,也无论多少人使用,需要收费
  • 可定制能力低,除了map组件提供的方法与属性以外,难以加入其他的方法

所以,如果能引入专业的地图库(GIS库),那自然是一个好选择

Web地图库(即WebGIS库)常用的有Leaflet、OpenLayers等,Leaflet非常轻量,所以笔者这里选择了这个库

这里还要回答一个问题,uniapp是否支持引入第三方库,尤其是这种需要显示出来的第三方库?

答案是可以,uniapp使用renderjs实现了在视图层操作dom,运行 for web 的 js库,具体可参考:renderjs | uni-app官网 (dcloud.net.cn)

2. 引入Leaflet

uniapp支持使用npm安装的node_modules,但是不能直接在项目文件夹下使用npm install <xxx>

所以,需要在一个空文件夹下使用npm insall leaflet,然后再将node_modules下的文件夹复制到uniapp的项目文件夹下

(笔者注:这真是个费解的过程,可以理解为uniapp只是支持搜索node_modules下库,但是不支持npm管理方式)

现在项目的目录结构如下:

image-20231110003439075

3. 创建一个map页面

现在创建一个地图页面,它的结构大致如下:

<template>
	<view>
         <!-- 这个view用于显示地图 -->
		<view id="map" class="map"></view>
        
         <!-- 这个view用于数据通信 -->
		<!-- 监听变量 mapData 的变化,mapData 发生改变时,调用 leaflet 模块的 reciveMessage 方法 -->
		<view :mapData="mapData" :change:mapData="leaflet.reciveMessage"></view>
         <!-- mapData、reciveMessage这些名字可以自定义,但是大致结构如此 -->
	</view>
</template>

<script>
// vue代码
</script>

<script module="leaflet" lang="renderjs">
// module名可以自定义,但lang得是renderjs
 
import "leaflet/dist/leaflet.css"
import L from "leaflet"

 // Leaflet操作代码
</script>

<style lang="scss" scoped>
// 样式代码
</style>

4. 示例代码

笔者这里的示例代码如下,实现了根据传入的数据绘制图形:

<template>
	<view>
		<nav-bar title="查看地图 "></nav-bar>
		<view id="map" class="map"></view>
		<!-- 监听变量 mapData 的变化,mapData 发生改变时,调用 leaflet 模块的 reciveMessage 方法 -->
		<view :mapData="mapData" :change:mapData="leaflet.reciveMessage"></view>
	</view>
</template>

<script>
export default {
	data() {
		return {
			mapData: null
		}
	},
	onLoad(opt) {
		try {
			this.mapData = JSON.parse(opt.mapData)
		} catch (e) {
			console.error("数据解析错误:", e)
		}
	},
	methods: {
		/**
		 * 接收 renderjs 传过来的数据
		 * @param {Object} data
		 */
		reciveMessage: function(data) {
			console.log(data)
			this.mapData = data
		}
	}
}
</script>

<script module="leaflet" lang="renderjs">
import "leaflet/dist/leaflet.css"
import L from "leaflet"

let map = null

export default {
	data() {
		return {
			mapData: null
		}
	},
	mounted() {
			map = L.map('map', {
				center: [36.262131, 120.356609],
				zoom: 12,
				minZoom: 4,
				maxZoom: 18,
				zoomControl: false,
				attributionControl: false
			})

			L.tileLayer('http://t0.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=9813be7882272b227babab98c39a64b6').addTo(map)

			this.sendMsg()
		},
	methods: {
		sendMsg() {
			// 向页面传参
			this.$ownerInstance.callMethod('reciveMessage', this.mapData)
		},
		reciveMessage(newValue, oldValue, ownerInstance, instance) {
			this.mapData = newValue
			this.drawMap(newValue)
		},
		drawMap(data){

			console.log(data)

			if(!data || !map) return

			switch(data.type){
				case "circle":
					L.circle(data.center, { radius: data.radius }).addTo(map)
					break
				case "polygon":
					L.polygon(data.positions).addTo(map)
					break
				case "point":
					L.circle(L.latLng(data.x, data.y), { weight: 10 , color: "#f00" }).addTo(map)
					break
				case "polyline":
					L.polyline(data.positions).addTo(map)
					break
			}
		}
	}
}
</script>

<style lang="scss" scoped>
.map {
	width: 100%;
	height: 100vh;
}
</style>

结果图如下:

image-20231110005156929

5. 参考资料

[1] renderjs | uni-app官网 (dcloud.net.cn)

[2] uniApp中使用leaflet地图组件踩坑记 - 掘金 (juejin.cn)