uniapp腾讯地图JavaScript Api,H5端和原生APP端可用

        因项目需要,在uniapp中集成使用腾讯地图,为了方便维护,希望通过一套代码实现H5和APP同时可用。H5显示相对简单,APP端比较麻烦,记录下实现过程

一、集成步骤

1.使用 renderjs

script标签使用renderjs,因为JavaScript Api需要调用DOM对象,APP需要使用renderjs技术,保证script运行在webview环境,才能调用DOM对象。

<script lang="renderjs" module="test">
</script>

2.引用地图script


导入腾讯地图JS脚本,因为腾讯地图js不是按照uniapp格式编写,所以不能直接import导入,需要包装成一个js插件,使用 Promise,js加载成功,调用resolve,js加载失败,调用reject。

创建loadJs.js 文件

function loadJs(src) {
  return new Promise((resolve,reject)=>{
    let script = document.createElement('script');
    script.type = "text/javascript";
    script.src= src;
    document.body.appendChild(script);
      
    script.onload = ()=>{
      resolve();
    }
    script.onerror = ()=>{
      reject();
    }
  }).catch((e) => {})
}
 
export default loadJs


在页面中使用

<script lang="renderjs" module="test">
    import loadJs from "../../common/loadJs.js"
    
    export default {

        data() {
            return {
                
            }
        },
        mounted(){
            console.log('renderjs初始化完毕')
            loadJs('https://map.qq.com/api/gljs?v=1.exp&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77').then(()=>{
                // 加载成功,进行后续操作
            })
        },
         methods: {
        }
    }
</script>

3.修改js,兼容uniapp

下载腾讯官网的例子,改造成uniapp兼容的格式。有两种方式,

方式一:

将官网例子中 script 封装成一个个的function,定义在 vue文件的 methods 中,这样就可以直接调用。

方式二:

将官网例子中 script 代码全部拷贝到一个js文件中,再把需要调用的 function 通过 export 关键字导出,在vue文件中进行 import 调用。

4.修改监听事件

腾讯官网例子都是web端的,点击事件都是click,H5端运行需要改成touchend,否则点击无响应

Web端

svg.addEventListener('click', this.onClick); web端用click事件

H5端

svg.addEventListener('touchend', this.onClick); // H5端用touchend事件

二、示例

腾讯官网例子

以自定义覆盖物 -> DOMOverlay 为例,实操下

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>DOMOverlay</title>
</head>
<script charset="utf-8" src="https://map.qq.com/api/gljs?libraries=tools&v=1.exp&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77"></script>
<style type="text/css">
    html,
    body {
        height: 100%;
        margin: 0px;
        padding: 0px;
    }

    #container {
        width: 100%;
        height: 100%;
    }
</style>

<body onload="initMap()">
	<div id="container"></div>
	<script>
		var SVG_NS = 'http://www.w3.org/2000/svg';
		// 自定义环状饼图 - 继承DOMOverlay
		function Donut(options) {
			TMap.DOMOverlay.call(this, options);
		}

		Donut.prototype = new TMap.DOMOverlay();

		// 初始化
		Donut.prototype.onInit = function(options) {
			this.position = options.position;
			this.data = options.data;
			this.minRadius = options.minRadius || 0;
			this.maxRadius = options.maxRadius || 50;
		};

		// 销毁时需解绑事件监听
		Donut.prototype.onDestroy = function() {
			if (this.onClick) {
				this.dom.removeEventListener(this.onClick);
			}
		};

		// 创建DOM元素,返回一个DOMElement,使用this.dom可以获取到这个元素
		Donut.prototype.createDOM = function() {
			let svg = document.createElementNS(SVG_NS, 'svg');
			svg.setAttribute('version', '1.1');
			svg.setAttribute('baseProfile', 'full');

			let r = this.maxRadius;
			svg.setAttribute('viewBox', [-r, -r, r * 2, r * 2].join(' '));
			svg.setAttribute('width', r * 2);
			svg.setAttribute('height', r * 2);
			svg.style.cssText = 'position:absolute;top:0px;left:0px;';

			let donut = createDonut(this.data, this.minRadius, this.maxRadius);
			svg.appendChild(donut);
          
          	// click事件监听
          	this.onClick = () => {
				// DOMOverlay继承自EventEmitter,可以使用emit触发事件
				this.emit('click');
			};
			// pc端注册click事件,移动端注册touchend事件
          	svg.addEventListener('click', this.onClick);
			return svg;
		};

		// 更新DOM元素,在地图移动/缩放后执行
		Donut.prototype.updateDOM = function() {
			if (!this.map) {
				return;
			}

			// 经纬度坐标转容器像素坐标
			let pixel = this.map.projectToContainer(this.position);

			// 使饼图中心点对齐经纬度坐标点
			let left = pixel.getX() - this.dom.clientWidth / 2 + 'px';
			let top = pixel.getY() - this.dom.clientHeight / 2 + 'px';
			this.dom.style.transform = `translate(${left}, ${top})`;
		};

		// 使用SVG创建环状饼图
		function createDonut(data, minRadius, maxRadius) {
			const colorList = [
				'#7AF4FF',
				'#67D7FF',
				'#52B5FF',
				'#295BFF'
			];
			let sum = data.reduce((prev, curr) => prev + curr, 0);
			let angle = 0;

			let group = document.createElementNS(SVG_NS, "g");
			data.forEach((d, i) => {
				let delta = d / sum * Math.PI * 2;
					color = colorList[i],
					r = maxRadius,
					startAngle = angle,
					endAngle = angle + delta;
				angle += delta;

				// 对每个数据创建一个扇形
				let fanShape = document.createElementNS(SVG_NS, 'path');
				fanShape.setAttribute('style', `fill: ${color};`);
				fanShape.setAttribute('d', [
					'M0 0',
					`L${r * Math.sin(startAngle)} ${-r * Math.cos(startAngle)}`,
					`A${r} ${r} 0 ${delta > Math.PI ? 1 : 0} 1 ${r * Math.sin(endAngle)} ${-r * Math.cos(endAngle)}`,
				].join(' ') + ' z');
				group.appendChild(fanShape);
			});

			// 在中心创建一个圆形
			let circleShape = document.createElementNS(SVG_NS, 'circle');
			circleShape.setAttribute('style', 'fill: #FFFFFF');
			circleShape.setAttribute('cx', 0);
			circleShape.setAttribute('cy', 0);
			circleShape.setAttribute('r', minRadius);
			group.appendChild(circleShape);

			// 绘制文字
			let textShape = document.createElementNS(SVG_NS, 'text');
			textShape.setAttribute('x', 0);
			textShape.setAttribute('y', '0.3em');
			textShape.setAttribute('text-anchor', 'middle');
			textShape.innerHTML = sum;
			group.appendChild(textShape);

			return group;
		}

		window.Donut = Donut;
	</script>
	<script type="text/javascript">
		var map;
        function initMap() {
            // 初始化地图
            map = new TMap.Map("container", {
                zoom:12, // 设置地图缩放级别
                center: new TMap.LatLng(39.984104, 116.307503) // 设置地图中心点坐标
			});

			let donutList = [
				new Donut({
					map,
					position: new TMap.LatLng(39.96030543872138, 116.25809083213608),
					data: [12, 24],
					minRadius: 13,
					maxRadius: 20
				}),
				new Donut({
					map,
					position: new TMap.LatLng(39.9986945980902, 116.33598362780685),
					data: [23, 99, 101, 400],
					minRadius: 25,
					maxRadius: 35
				}),
				new Donut({
					map,
					position: new TMap.LatLng(40.02906301748584, 116.25499991104516),
					data: [18, 41, 50],
					minRadius: 20,
					maxRadius: 28
				})
			];

			donutList.forEach((donut, index) => {
				donut.on('click', () => {
					console.log(`第${index}个环形图被点击,位置为${donut.position}`);
				});
			});
		}
    </script>
</body>

</html>

适配后uniapp代码

主要三个文件 DOMOverlay.js、loadJs.js、map.vue

DOMOverlay.js 

一般来说先把script 全部复制到一个单独js文件,然后直接运行,运气好直接正常使用,运气不好就哪里报错改哪里,DOMOverlay.js文件修改过我都加了注释“适配uniapp修改过的”

var SVG_NS = 'http://www.w3.org/2000/svg';
// 自定义环状饼图 - 继承DOMOverlay
function Donut(options) {
	TMap.DOMOverlay.call(this, options);
}


/** 
 * ----------------适配uniapp修改过的----------------
 * 
 * 因为 TMap 对象依赖于 https://map.qq.com/api/gljs?v=1.exp&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77 
 * 所以要封装一个方法,在加载完依赖脚本后,再运行
 */
function initDonut(){
	Donut.prototype = new TMap.DOMOverlay();
	
	// 初始化
	Donut.prototype.onInit = function(options) {
		this.position = options.position;
		this.data = options.data;
		this.minRadius = options.minRadius || 0;
		this.maxRadius = options.maxRadius || 50;
	};
	
	// 销毁时需解绑事件监听
	Donut.prototype.onDestroy = function() {
		if (this.onClick) {
			this.dom.removeEventListener(this.onClick);
		}
	};
	
	// 创建DOM元素,返回一个DOMElement,使用this.dom可以获取到这个元素
	Donut.prototype.createDOM = function() {
		let svg = document.createElementNS(SVG_NS, 'svg');
		svg.setAttribute('version', '1.1');
		svg.setAttribute('baseProfile', 'full');
	
		let r = this.maxRadius;
		svg.setAttribute('viewBox', [-r, -r, r * 2, r * 2].join(' '));
		svg.setAttribute('width', r * 2);
		svg.setAttribute('height', r * 2);
		svg.style.cssText = 'position:absolute;top:0px;left:0px;';
	
		let donut = createDonut(this.data, this.minRadius, this.maxRadius);
		svg.appendChild(donut);
	  
		// click事件监听
		this.onClick = () => {
			// DOMOverlay继承自EventEmitter,可以使用emit触发事件
			this.emit('click');
		};
		// ----------------适配uniapp修改过的----------------
		// pc端注册click事件,移动端注册touchend事件
		// svg.addEventListener('click', this.onClick); web端用click事件
		svg.addEventListener('touchend', this.onClick); // H5端用touchend事件
		return svg;
	};
	
	// 更新DOM元素,在地图移动/缩放后执行
	Donut.prototype.updateDOM = function() {
		if (!this.map) {
			return;
		}
	
		// 经纬度坐标转容器像素坐标
		let pixel = this.map.projectToContainer(this.position);
	
		// 使饼图中心点对齐经纬度坐标点
		let left = pixel.getX() - this.dom.clientWidth / 2 + 'px';
		let top = pixel.getY() - this.dom.clientHeight / 2 + 'px';
		this.dom.style.transform = `translate(${left}, ${top})`;
	};
}

// 使用SVG创建环状饼图
function createDonut(data, minRadius, maxRadius) {
	const colorList = [
		'#7AF4FF',
		'#67D7FF',
		'#52B5FF',
		'#295BFF'
	];
	let sum = data.reduce((prev, curr) => prev + curr, 0);
	let angle = 0;

	let group = document.createElementNS(SVG_NS, "g");
	data.forEach((d, i) => {
		let delta = d / sum * Math.PI * 2;
			let color = colorList[i],
			r = maxRadius,
			startAngle = angle,
			endAngle = angle + delta;
		angle += delta;

		// 对每个数据创建一个扇形
		let fanShape = document.createElementNS(SVG_NS, 'path');
		fanShape.setAttribute('style', `fill: ${color};`);
		fanShape.setAttribute('d', [
			'M0 0',
			`L${r * Math.sin(startAngle)} ${-r * Math.cos(startAngle)}`,
			`A${r} ${r} 0 ${delta > Math.PI ? 1 : 0} 1 ${r * Math.sin(endAngle)} ${-r * Math.cos(endAngle)}`,
		].join(' ') + ' z');
		group.appendChild(fanShape);
	});

	// 在中心创建一个圆形
	let circleShape = document.createElementNS(SVG_NS, 'circle');
	circleShape.setAttribute('style', 'fill: #FFFFFF');
	circleShape.setAttribute('cx', 0);
	circleShape.setAttribute('cy', 0);
	circleShape.setAttribute('r', minRadius);
	group.appendChild(circleShape);

	// 绘制文字
	let textShape = document.createElementNS(SVG_NS, 'text');
	textShape.setAttribute('x', 0);
	textShape.setAttribute('y', '0.3em');
	textShape.setAttribute('text-anchor', 'middle');
	textShape.innerHTML = sum;
	group.appendChild(textShape);

	return group;
}

window.Donut = Donut;

var map;
function initMap() {
    // ----------------适配uniapp修改过的----------------
    // 调用封装后的initDount()
	initDonut()
	
	// 初始化地图
	map = new TMap.Map("mapContainer", {
		zoom:12, // 设置地图缩放级别
		center: new TMap.LatLng(39.984104, 116.307503) // 设置地图中心点坐标
	});

	let donutList = [
		new Donut({
			map,
			position: new TMap.LatLng(39.96030543872138, 116.25809083213608),
			data: [12, 24],
			minRadius: 13,
			maxRadius: 20
		}),
		new Donut({
			map,
			position: new TMap.LatLng(39.9986945980902, 116.33598362780685),
			data: [23, 99, 101, 400],
			minRadius: 25,
			maxRadius: 35
		}),
		new Donut({
			map,
			position: new TMap.LatLng(40.02906301748584, 116.25499991104516),
			data: [18, 41, 50],
			minRadius: 20,
			maxRadius: 28
		})
	];

	donutList.forEach((donut, index) => {
		donut.on('click', () => {
			console.log(`第${index}个环形图被点击,位置为${donut.position}`);
			alert(`第${index}个环形图被点击,位置为${donut.position}`)
		});
	});
}

/**
 * ----------------适配uniapp修改过的----------------
 * 导出initMap方法
 */ 
export {
	initMap
}
loadJs.js

用来加载第三方js

function loadJs(src) {
  return new Promise((resolve,reject)=>{
    let script = document.createElement('script');
    script.type = "text/javascript";
    script.src= src;
    document.body.appendChild(script);
      
    script.onload = ()=>{
      resolve();
    }
    script.onerror = ()=>{
      reject();
    }
  }).catch((e) => {})
}
 
export default loadJs
map.vue
<template>
	<view id="mapContainer" style="height: 100%;" @click="log">
	</view>
</template>

<script>
	export default {
		data() {
			return {
				
			}
		},
		mounted() {
			
		}
		
	}
</script>

<script lang="renderjs" module="test">
	
	import loadJs from "../../common/loadJs.js"
    // 导入适配后的 DOMOverlay.js
	import {initMap} from "../../common/DOMOverlay.js"
	
	export default {

		data() {
		    return {
				
			}
		},
		mounted(){
			console.log("mounted") 
			loadJs('https://map.qq.com/api/gljs?v=1.exp&key=OB4BZ-D4W3U-B7VVO-4PJWW-6TKDJ-WPB77').then(()=>{
				// 调用初始化地图方法
				initMap()
			})
		},
		 methods: {
		}, 
		created() {
			
		}
	}
</script>

<style>
   
</style>

三、适配效果

APP运行效果图,与官网一致

  • 6
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值