上次提到uniapp开发地图app时得一些问题,最后提到使用renderjs实现app中使用任何地图(下面将以腾讯地图为例,uniapp中写app时推荐使用得是高德地图,无法使用腾讯地图(renderjs方式除外))。
1、renderjs介绍,这里直接参照uniapp开发官网介绍即可:renderjs | uni-app官网
官网也有示例,示例是使用echart得,不过使用方法和地图相类似。
下面先看一下demo效果:
这是一个app中使用地图得makers,点击单个makers会显示对应得图片在上面,并且点击得maker会被放大,这个功能使用uniapp得map组件时是会有很大得问题得,再次就不再赘述。下面看看代码实现。
1、先来看看整个页面得组成(文章最后附上相关示例代码):
从上面可以看到script标签有两个,一个是普通得script标签,另一个是lang="renderjs"得标签。
2、注意事项:上面提到得renderjs中,module得名字需要和template上得标签名称一致,如图:
mapModule.update中update是该模块下面得一个方法。
3、接下来介绍一下
html
<view class="curr" id="container" :prop="mapModel" :change:prop="mapModule.update"></view>
改代码,mapModel为script普通标签里面得一个响应式变量
:change:prop="mapModule.update" 含义,当script里面得mapModel数据发生变化时,会通过该处触发renderjs里面得update方法。
4、renderjs中不能使用http请求,相关请求只能放在普通标签里面,renderjs仅根据数据变化做逻辑处理(可以理解为一个子组件)
5、最后附上相关代码(mapDemo.vue):
javascript
<template>
<view class="index-wrap">
<view class="curr-position" @click="mapModule.setPosition">
<image src="../../static/mapImg/5.png"></image>
</view>
<view class="curr" id="container" :prop="mapModel" :change:prop="mapModule.update"></view>
</view>
</template>
<script>
export default {
components: { IndexTabs, UpdateApp },
data() {
return {
showMenu: false,
id: 0, // 使用 marker点击事件 需要填写id
mapModel: {}
};
},
computed: {
getShow() {
if (this.showMenu) {
return true;
} else {
const timer = setTimeout(() => {
clearTimeout(timer);
return false;
}, 3000)
}
}
},
methods: {
init() {
this.mapModel = {
markerLatlng: [{ lat: 40.77460069719003, lng: 114.8868407358159 },
{ lat: 40.7746130606868, lng: 114.88729786752276 },
{ lat: 40.7746130606868, lng: 114.88739786752276 },
{ lat: 40.77465839357235, lng: 114.88736317180303 },]
}
}
}
};
</script>
<script module="mapModule" lang="renderjs">
import {
initScript,
getMap,
getLatLng,
getMultiMarker,
getGeometriesItem,
getFitBounds
} from '../../utils/tmap';
import {getPosition} from '../../utils/utils';
export default {
data() {
return {
ownerInstance: null,
map: null,
center: null,
marker: null,
infoWindow: null,
currPosition: {},
mapModel: {},
};
},
methods: {
async setPosition(){
this.currPosition = await getPosition()
this.center = getLatLng(this.currPosition.lat, this.currPosition.lng)
this.map.setCenter(this.center)
},
init(){
this.ownerInstance.ownerInstance('init')
},
async refresh() {
// 待处理
if(this.mapModel.markerLatlng.length){
const first = this.mapModel.markerLatlng[0]
this.center = getLatLng(first.lat, first.lng)
}
if(this.map){
getFitBounds(this.map, this.mapModel.markerLatlng)
}else{
this.map = getMap(this.center);
}
getFitBounds(this.map, this.mapModel.markerLatlng, 0.2)
this.marker = getMultiMarker(this.map, this.mapModel.markerLatlng.map((item, index )=> getGeometriesItem(item, 'marker'+index)))
this.marker.on('click', this.onMarker)
},
onMarker(e){
const markers = this.marker.geometries.map(item => item.id === e.geometry.id ? {...item, styleId: 'currMarker'} : {...item, styleId: 'marker'})
this.marker.updateGeometries(markers)
this.dealInfoWindow(e.geometry.position)
},
dealInfoWindow(center){
if(this.infoWindow){
this.infoWindow.close()
}
this.infoWindow = new TMap.InfoWindow({
map: this.map,
position: center,
offset: {x: 0, y: -80},
content: "<div><img src='https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/em.jpg'></div>"
});
},
update(newValue, _, ownerInstance) {
this.mapModel = newValue
if (this.ownerInstance) {
this.refresh()
} else {
this.ownerInstance = ownerInstance;
initScript(this.init)
}
}
}
};
</script>
<style lang="scss" scoped>
.index-wrap {
height: 100vh;
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
.curr-position {
position: fixed;
bottom: 340rpx;
right: 32rpx;
z-index: 1001;
display: flex;
justify-content: center;
align-items: center;
background: #fff;
border-radius: 12rpx;
height: 80rpx;
width: 80rpx;
image {
display: inline-block;
width: 48rpx;
height: 48rpx;
}
}
.curr {
display: flex;
justify-content: center;
align-items: center;
flex: 1;
}
.map-container {
flex: 1;
width: 100%;
height: 100%;
z-index: 100;
display: block;
// transition: all 0 ease-in-out 0;
&.active {
display: none;
// transition: all 0 ease-in-out 0.3s;
}
// margin-top: 200rpx;
}
}
</style>
下面时renderjs中引入得utils.js和tmap.js:
utils.js
javascript
/**
* @description 通过uni.getLocation获取相关地理信息
* @returns
*/
export function getPosition() {
return new Promise((resolve) => {
uni.getLocation({
type: "gcj02",//"wgs84",
geocode: true,
timeout: 6,
fail: () => {
resolve({ ...getLocationLatLng(), errMsg: "getLocation:fail" });
},
success: (res) => {
const {province, city, district, street, streetNum, poiName} = res.address
const params = {
...res,
latitude: res.latitude,
longitude: res.longitude,
address_info: `${province}${city}${district}${street}${streetNum}`,
address: poiName,
};
uni.setStorageSync("LatLng", JSON.stringify(res));
resolve(params);
},
});
const timer = setTimeout(() => {
clearTimeout(timer);
resolve({ ...getLocationLatLng(), errMsg: "getLocation:fail" });
}, 1000);
});
}
tmap.js: (key值需要替换成你自己项目中地图的key)
javascript
import {icon1} from './mapIcon'
const key = '此处为你申请的腾讯地图得key'
export function getLocation() {
return new TMap.maps.Geolocation(key, "腾讯地图API示例")
}
export function initScript(callback) {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://map.qq.com/api/gljs?v=1.exp&key=" + key;
// script.src = "https://map.qq.com/api/js?v=2.exp&key=";
document.body.appendChild(script);
script.onload = () => {
callback()
}
}
export function getMap(center, id, zoom = 15) {
return new TMap.Map(document.getElementById(id || 'container'), {
center,//设置地图中心点坐标
zoom, //设置地图缩放级别
showControl: false,
})
}
/**
*
* @param {Number} lat 经度
* @param {Number} lng 维度
* @returns
*/
export function getLatLng(lat, lng) {
return new TMap.LatLng(lat, lng);
}
/**
* @description 获取路径数组
* @param {Array} pathList 经纬度数组
* @returns
*/
export function getPath(pathList) {
return pathList.map(item => getLatLng(item.lat, item.lng));
}
/**
* @description 地图设置会放路径
* @param {Object} map 地图对象
* @param {Array} pathList 路径数组
* @returns
*/
export function getPolylineLayer(map, pathList) {
return new TMap.MultiPolyline({
map, // 绘制到目标地图
// 折线样式定义
styles: {
style_blue: new TMap.PolylineStyle({
color: '#3777FF', // 线填充色
width: 4, // 折线宽度
borderWidth: 2, // 边线宽度
borderColor: '#FFF', // 边线颜色
lineCap: 'round', // 线端头方式
eraseColor: 'rgba(190,188,188,1)',
}),
},
geometries: [
{
id: 'erasePath',
styleId: 'style_blue',
paths: getPath(pathList),
},
],
})
}
/**
*
* @param {Object} LatLng 经纬度对象{lat,lng}
* @param {String} id 标注点Id
* @param {String} styleId 样式id
* @returns
*/
export function getGeometriesItem(LatLng, id, styleId = 'marker') {
return { //点标注数据数组
id,
styleId,
"position": getLatLng(LatLng.lat, LatLng.lng),
// "properties": {
// "title": "marker"
// }
}
}
export function getMarkerUrlByType(type) {
return 'static/mapImg/marker.png'
}
export function getMarkerStyle(key, src, width = 70, height = 70) {
return {
[key]: new TMap.MarkerStyle({
width,
height,
src,
})
}
}
export function getMultiMarker(map, geometries) {
return new TMap.MultiMarker({
id: "marker-layer", //图层id
map,
styles: { //点标注的相关样式
...getMarkerStyle('marker', icon1),
...getMarkerStyle('currMarker', icon1, 90, 90),
'car': new TMap.MarkerStyle({
width: 40,
height: 40,
anchor: {
x: 20,
y: 20,
},
faceTo: 'map',
rotate: 180,
src: icon1
// src: 'https://mapapi.qq.com/web/lbs/javascriptGL/demo/img/car.png',
})
},
geometries
});
}
function getfitBoundItemNum(base, add){
return base + add
}
/**
*
* @param {Object} map 地图对象
* @param {Array} latlngList 坐标点集合,示例:[{lat: 0, lng: 0}]
*/
export function getFitBounds(map, latlngList, scale = 1) {
let latlist = []
let lnglist = []
latlngList.forEach(item => {
latlist.push(item.lat)
lnglist.push(item.lng)
})
const latMax = Math.max(...latlist)
const latMin = Math.min(...latlist)
const lngMax = Math.max(...lnglist)
const lngMin = Math.min(...lnglist)
const latDiff = (latMax - latMin) * scale
const lngDiff = (lngMax - lngMin) * scale
const ne = getLatLng(getfitBoundItemNum(latMax, latDiff), getfitBoundItemNum(lngMax, lngDiff))
const sw = getLatLng(getfitBoundItemNum(latMin, -latDiff*2.5), getfitBoundItemNum(lngMin, -lngDiff))
const latLngBounds = new TMap.LatLngBounds(sw, ne)
map.fitBounds(latLngBounds); //根据指定的范围调整地图视野
}
mapIcon.js(图片base64字符串),注意:腾讯地图中图片地址必须是绝对地址,如果你们可以使用相对地址,欢迎留言讨论:
javascript
export const icon1 = `data:image/png;base64,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`