uniapp使用地图开发app, renderjs使用方法及注意事项

上次提到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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`
相关推荐
旧味清欢|9 分钟前
关注分离(Separation of Concerns)在前端开发中的实践演进:从 XMLHttpRequest 到 Fetch API
javascript·http·es6
热爱编程的小曾27 分钟前
sqli-labs靶场 less 8
前端·数据库·less
gongzemin38 分钟前
React 和 Vue3 在事件传递的区别
前端·vue.js·react.js
Apifox1 小时前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
-代号95271 小时前
【JavaScript】十四、轮播图
javascript·css·css3
树上有只程序猿1 小时前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼2 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
QTX187302 小时前
JavaScript 中的原型链与继承
开发语言·javascript·原型模式
黄毛火烧雪下2 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员