上次提到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、接下来介绍一下
<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):
<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点击事件 需要填写idmapModel: {}};},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 = newValueif (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
/*** @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.addressconst 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)
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", //图层idmap,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) * scaleconst lngDiff = (lngMax - lngMin) * scaleconst 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字符串),注意:腾讯地图中图片地址必须是绝对地址,如果你们可以使用相对地址,欢迎留言讨论:
export const icon1 = `data:image/png;base64,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`