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

news/2025/2/12 20:06:49/

        因项目需要,在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';// 自定义环状饼图 - 继承DOMOverlayfunction 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.jsimport {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运行效果图,与官网一致


http://www.ppmy.cn/news/1361010.html

相关文章

golang实现延迟队列(delay queue)

golang实现延迟队列 1 延迟队列&#xff1a;邮件提醒、订单自动取消 延迟队列&#xff1a;处理需要在未来某个特定时间执行的任务。这些任务被添加到队列中&#xff0c;并且指定了一个执行时间&#xff0c;只有达到指定的时间点时才能从队列中取出并执行。 应用场景&#xff1…

P8630 [蓝桥杯 2015 国 B] 密文搜索

P8630 [蓝桥杯 2015 国 B] 密文搜索 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P8630 题目分析 基本上是hash的板子&#xff0c;但实际上对于密码串&#xff0c;只要判断主串中任意连续的八个位置是否存在密码串即可&#xff1b;那么我们…

CiteSpace for Mac 最新保姆级教程

CiteSpace需要在Java的环境下运行&#xff0c;上篇文章分享了Java入门操作&#xff0c;安装好Java后&#xff0c;就可以下载安装文献分析神器CiteSpace。​​​​​​​ 注意&#xff01;&#xff01;CiteSpace的版本是要和Java版本匹配的。比如&#xff1a;要安装CiteSpace&a…

【Java程序设计】【C00286】基于Springboot的生鲜交易系统(有论文)

基于Springboot的生鲜交易系统&#xff08;有论文&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的生鲜交易系统 本系统分为系统功能模块、管理员功能模块、用户功能模块以及商家功能模块。 系统功能模块&#xff1a;在系统首页可以…

85、字符串操作的优化

上一节介绍了在模型的推理优化过程中,动态内存申请会带来额外的性能损失。 Python 语言在性能上之所以没有c++高效,有一部分原因就在于Python语言将内存的动态管理过程给封装起来了,我们作为 Python 语言的使用者是看不到这个过程的。 这一点有点类似于 c++ 标准库中的一些…

3_怎么看原理图之协议类接口之I2C笔记

I2C只连接I2CSCL与I2CSDA两根线&#xff0c;即2线制异步串行总线。 I2CSCL与I2CSDA两根线需要上拉电阻&#xff0c;目的是让电平有确定的状态。 发完8bit数据后&#xff0c;第9个电平拉低SDA为低电平。 比如传一个数据A0x410100 0001 IIC总线有多个从机设备的通信&#xff0c…

Atcoder ABC341 A-D题解

比赛链接:ABC341 Problem A: 先签个到。 #include <bits/stdc.h> using namespace std; int main() {int n;cin>>n;for(int i0;i<n;i)cout<<"10"<<endl;cout<<"1"<<endl;return 0; } Problem B: 继续签。 #i…

RocketMQ(七):跟着官网学习敲代码(备份)

接上篇&#xff1a;RocketMQ&#xff08;六&#xff09;&#xff1a;跟着官网学习敲代码 1 定时消息 在/bin目录下执行以下命令&#xff0c;创建定时主题&#xff1a; sh mqadmin updateTopic -c DefaultCluster -t DelayTopic001 -o true -n 127.0.0.1:9876 -a message.type…