目录
- 任务
- 效果图
- 生成页面
- 顶部标题
- tab切换
- 地图画布
- map.html页面设置
- 实现页面通信,分解url参数
- 初始化地图
- 点聚合功能实现
- 搜索功能实现
- 总结
任务
在工作中接到的一个任务,在app端实现如下功能:
- 地图点聚合
- 地图页面支持tab切换(设备、劳务、人员)
- 支持人员搜索显示分布
但是uniapp原有的map标签不支持点聚合功能(最新的版本支持了点聚合功能),所以采取了hybrid 原生html文件开发的方式
最新的版本map已支持,如下:
效果图
h5的效果图,与真机有点偏差
生成页面
在pages.json中定义distribution.vue页面
{ | |
"path": "pages/distribution/distribution", | |
"style": { | |
"navigationBarTitleText": "人机分布", | |
"navigationBarTextStyle": "black" | |
} | |
}, |
页面结构主要分为三个部分:顶部标题,tab切换,地图画布
顶部标题
顶部标题就不用讲了,一般打开微信小程序页面或者app页面,都是左—返回,中—标题,右—其他。存在默认设置,但这里的话存在web-view(web 浏览器组件,可以用来承载网页的容器),很有可能将顶部标题覆盖掉,所以使用自定义标题,具体实现如下:
<view class="tab"> | |
<!-- :isBack="true" --> | |
<tab-left bgColor="bg-gradual-white" :isBack="true" :url="gobackurl"> | |
<block slot="backText">返回</block> | |
<block slot="content">人机分布</block> | |
</tab-left> | |
</view> |
tab切换
主要实现设备/劳务/人员的tab切换,固定在app内容顶部,难点在于tab切换时,需要实现页面和html页面通信,改变地图内容,主要需要做以下几个功能:
- 调用接口(getNavInfo)获取maplists信息
// 获取导航栏数值 | |
getNav(){ | |
let params={ | |
ProjectId:this.projectId, | |
OrgCode:this.orgcode | |
} | |
Api.getNavInfo(params).then(res=>{ | |
console.log('嘻嘻',res) | |
if(res.data.length>){ | |
res.data.forEach((item,index)=>{ | |
this.maplists[index].number=item | |
}) | |
}else{ | |
uni.showToast({ | |
title:'获取导航栏数值失败', | |
icon:'none' | |
}) | |
} | |
}) | |
}, |
- 切换tab时,实现与页面和html的通信
swichNav(item) { | |
// this.reportisChoose = parseInt(e.currentTarget.id -); | |
// this.url += encodeURIComponent(JSON.stringify([{'s':}])); | |
item.check=!item.check | |
if(item.check){ | |
this.maker.push(item.id) | |
}else{ | |
let index= | |
this.maker.forEach((x,i)=>{ | |
if(x===item.id){ | |
index=i | |
} | |
}) | |
this.maker.splice(index,) | |
} | |
console.log('this.makerxxx',this.maker) | |
this.url ='../../hybrid/html/map.html?'+ "access_token="+this.token+"&maker="+JSON.stringify(this.maker)+"&baseUrl="+this.baseUrl+"&projectId=" + this.projectId+"&OrgCode="+this.orgcode | |
}, |
地图画布
地图画布主要是嵌入map.html,这里主要是用到了web-view,需要注意以下两个地方:
- web-view:一般是占满全屏的,优先级最高,所以会覆盖tab部分,故要设定高度或者top值,
主要实现如下:
// 获取设备信息 | |
getEqData() { | |
let _this=this | |
console.log('进来来'); | |
let projectId = this.$store.state.user.projectId; | |
Api.getEqlocation(projectId).then(res => { | |
if (res.data.success) { | |
this.eqData = res.data.data; | |
console.log('结果是', this.eqData); | |
this.eqData.forEach(item=>{ | |
item['x']=this.longitude+Math.random(,1000) | |
item['y']=this.latitude+Math.random(,1000) | |
item['text']='设备信息' | |
item['path']='../../static/.png' | |
}) | |
} | |
}) | |
}, | |
// 获取屏幕高度 | |
getwh() { | |
const { windowWidth, windowHeight } = uni.getSystemInfoSync(); | |
console.log('windowWidth, windowHeight', windowWidth, windowHeight); | |
this.height = windowHeight; | |
this.width = windowWidth; | |
let _this = this; | |
this.$nextTick(function() { | |
this.computeHeight(); | |
this.setWebHeight() | |
}); | |
}, | |
// 设置web-view样式 | |
setWebHeight(){ | |
let _this=this | |
console.log('height',this.$scope) | |
// #ifdef APP-PLUS | |
var currentWebview = this.$scope.$getAppWebview(); //获取当前web-view | |
setTimeout(function(){ | |
var wv = currentWebview.children()[]; | |
console.log('wv',wv); | |
wv.setStyle({ | |
//设置web-view距离顶部的距离以及自己的高度,单位为px | |
top: _this.top, | |
height: _this.height, | |
// 双指缩放 | |
scalable:true | |
}); | |
},) | |
// #endif | |
}, | |
// 计算导航栏和顶部高度 | |
computeHeight() { | |
let _this = this; | |
let info = uni.createSelectorQuery().select('.map-top-tab'); | |
info.boundingClientRect(function(data) { | |
console.log('计算出来什么高度', data); | |
_this.top = data.height; | |
}).exec(); | |
let info=uni.createSelectorQuery().select('.tab') | |
info.boundingClientRect(function(data) { | |
console.log('计算出来什么高度', data); | |
_this.top += data.height; | |
_this.height = _this.height-_this.top; | |
}).exec(); | |
console.log('sssssssssssssssss',this.height,this.top) | |
} |
- web-view嵌入本地网页,主要放在../../hybrid/html 文件下,这个官网给出了建议和结构图,如下:
┌─components
├─hybrid
│ └─html
│ ├─css
│ │ └─test.css
│ ├─img
│ │ └─icon.png
│ ├─js
│ │ └─test.js
│ └─local.html
├─pages
│ └─index
│ └─index.vue
├─static
├─main.js
├─App.vue
├─manifest.json
└─pages.json
map.html页面设置
虽然是个html页面,但主要是实现地图点聚合(主要使用百度地图api实现) 的功能,所以主要要引入以下几个依赖:
<link rel="stylesheet" href="https//api.map.baidu.com/library/SearchInfoWindow/.5/src/SearchInfoWindow_min.css" rel="external nofollow" /> | |
<script type="text/javascript" src="https://api.map.baidu.com/api?v=.0&ak=Ps5KaIdB9sSNUbDwECgTtBL7xluVv91s"></script> | |
<script src="//libs.baidu.com/jquery/.9.0/jquery.js"></script> | |
<script type="text/javascript" src="https://api.map.baidu.com/library/TextIconOverlay/.2/src/TextIconOverlay_min.js"></script> | |
<script type="text/javascript" src="js/MakerClusterer.js"></script> | |
<script src="js/vue.min.js"></script> | |
<script src="js/axios.js"></script> |
实现页面通信,分解url参数
created() { | |
axios.defaults.headers.post['Content-Type'] = 'application/json'; | |
let _this = this | |
this.baseUrl = this.getQueryString('baseUrl') | |
this.projectId = this.getQueryString('projectId'); | |
this.access_token_app = this.getQueryString('access_token'); | |
this.OrgCode = this.getQueryString('OrgCode') | |
// console.log('传过来的数据', this.baseUrl, this.projectId, this.access_token_app, this.OrgCode) | |
localStorage.setItem('baseUrl', this.baseUrl) | |
localStorage.setItem('access_token_app', this.access_token_app) | |
axios.defaults.headers.common['Authorization'] = "Bearer " + localStorage.getItem('access_token_app') | |
this.maker = this.getQueryString('maker') | |
// console.log('this.maker', this.maker) | |
this.maker = JSON.parse(this.maker) | |
// console.log('this.maker', this.maker) | |
if (this.maker !== null) { | |
//--设备,2--劳务,3--人员 | |
this.maker.forEach(y => { | |
//--设备,2--劳务,3--人员 | |
switch (y) { | |
case: | |
console.log('进入设备区域了') | |
_this.getEqData() | |
break | |
case: | |
console.log('进入劳务区域了') | |
_this.getServiceData() | |
break | |
case: | |
console.log('进入人员区域了') | |
_this.getUserData() | |
break | |
} | |
}) | |
} | |
this.$nextTick(function() { | |
_this.initMap() | |
}) | |
}, | |
mounted() { | |
document.addEventListener('UniAppJSBridgeReady', function() { | |
uni.getEnv(function(res) { | |
console.log('当前环境:' + JSON.stringify(res)); | |
}); | |
}); | |
}, | |
methods:{ | |
//取url中的参数值 | |
getQueryString(name) { | |
// 正则:[找寻'&' + 'url参数名字' = '值' + '&']('&'可以不存在) | |
var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i'); | |
let r = window.location.search.substr().match(reg); | |
if (r != null) { | |
// 对参数值进行解码 | |
return r[] | |
} | |
return null; | |
}, | |
} |
初始化地图
// 初始化地图 | |
initMap() { | |
// 百度地图API功能 | |
this.map = new BMap.Map("allmap"); | |
// 初始化地图,创建中心坐标和地图实例 | |
this.map.centerAndZoom(new BMap.Point(.331398, 39.897445), 10); | |
// this.map.addEventListener("tilesloaded",function(){alert("地图加载完毕");}) | |
// 启用拖拽 | |
// this.map.enableInertialDragging() | |
// this.map.enableScrollWheelZoom(); | |
// 启用双指缩放 | |
// this.map.enablePinchToZoom() | |
// this.map.addControl(new BMap.NavigationControl()); | |
this.map.addControl(new BMap.ScaleControl()); | |
this.map.addControl(new BMap.OverviewMapControl()); | |
let temMap = this.map | |
// 添加带有定位的导航控件,放大,缩小 | |
var navigationControl = new BMap.NavigationControl({ | |
// 靠左上角位置 | |
anchor: BMAP_ANCHOR_TOP_RIGHT, | |
// 偏移值 | |
offset: new BMap.Size(, 50), | |
// LARGE类型 | |
type: BMAP_NAVIGATION_CONTROL_LARGE, | |
// 是否显示级别 | |
showZoomInfo: true, | |
// 启用显示定位 | |
enableGeolocation: true | |
}); | |
this.map.addControl(navigationControl); | |
// 添加定位控件 | |
var geolocationControl = new BMap.GeolocationControl(); | |
geolocationControl.addEventListener("locationSuccess", function(e) { | |
// 定位成功事件 | |
var address = ''; | |
address += e.addressComponent.province; | |
address += e.addressComponent.city; | |
address += e.addressComponent.district; | |
address += e.addressComponent.street; | |
address += e.addressComponent.streetNumber; | |
}); | |
geolocationControl.addEventListener("locationError", function(e) { | |
// 定位失败事件 | |
alert(e.message); | |
}); | |
this.map.addControl(geolocationControl); | |
}, |
点聚合功能实现
主要起作用的是MarkerClusterer类
watch: { | |
markerArr(val) { | |
if (val != null) { | |
console.log('ccccc', val) | |
if (this.markerClusterer) { | |
this.markerClusterer.clearMarkers() | |
} | |
this.markerClusterer = new BMapLib.MarkerClusterer(this.map, { | |
markers: val | |
}); | |
// 所有标记显示在地图内 | |
this.map.setViewport(this.pointArray) | |
console.log('当前地图级别', this.map.getZoom()) | |
} | |
}, | |
} |
搜索功能实现
// 根据名称搜索项目 | |
searchByName() { | |
console.log('运动少杀杀杀', this.arrAll) | |
let markerByName = this.arrAll.filter(item => item.name.indexOf(this.keyword) !== -) | |
console.log('过滤后的照片', markerByName) | |
if (markerByName.length ===) { | |
alert('搜索内容无定位信息,请重新搜索') | |
this.keyword = '' | |
return | |
} | |
// 设置最大级别数 | |
// this.map.setMaxZoom() | |
this.markerArr = [] | |
this.createDefineMarker(markerByName) | |
this.map.setViewport(this.pointArray) | |
console.log('当前地图级别', this.map.getZoom()) | |
}, |