uni-app引入天地图打包成app后,兼容安卓。该方式仅兼容安卓、h5,微信小程序需要用到其他方案。
安卓模拟器最终效果
uni-app提供的<map>组件,仅支持下面的服务商,想使用天地图或其他地图,需要搭配地图引擎使用。
本案例使用工具与插件
- leaflet.js 轻量的地图引擎,获取无需魔法
- uni-app
- HbuilderX 3.8.3
- MuMu模拟器12 (用于查看实时运行效果)
实现思路
- uni-app提供的map组件中,仅支持腾讯、百度、高德三个平台的地图,想要切换成天地图需要使用另外的地图渲染引擎来实现。
- h5端的兼容是最好做的,app与小程序端不支持dom操作,需要另想办法渲染。
- 地图渲染引擎使用的是 leaflet,相较于其他渲染引擎,它的主体代码比较小。
- 因为app端不支持dom的操作,使用leaflet 官方提供的渲染方式会出现不渲染情况。这时候需要配合 uni-app 中的renderjs来配合渲染。
- renderjs 改变了uni-app的渲染模式,在逻辑层之外加上了一个视图层,二者之间互不通信,需要搭配官方提供的通信方式进行通信,同时值得注意的是,二者之间的通信只能是JSON格式的,其他的格式均不支持。
引入步骤
- 将 leaflet.js 放在 static中,注意路径。如果跟j-leaflet路径不一致,需要改一下。
- 将 leaflet.css 放在 static中,并引入uni.scss
- 将 j-leaflet 文件夹放在 components
-
放置目录结构
引用 j-leaflet 组件demo
<template>
<view>
<!-- #ifndef MP-WEIXIN -->
<!-- 除了微信均使用 -->
<leaflet @changeView="changeView" :location="location" :data="marker"></leaflet>
<!-- #endif -->
<!-- #ifdef MP-WEIXIN -->
<!-- #endif -->
</view>
</template>
<script>
import leaflet from '@/components/j-leaflet/j-leaflet.vue'
export default {
components: {
leaflet
},
data() {
var _this = this
return {
latitude: 39.909,
longitude: 116.39742,
marker:[],
location:{}
}
},
mounted() {
setTimeout(()=>{
this.location = {
latitude: 39.909,
longitude: 116.39742,
}
this.marker =[this.location]
},2230)
// this.init()
},
methods: {
changeView(){
console.log(12)
let list = {
latitude: 39.901,
longitude: 116.39712,
}
this.marker = [this.location]
},
}
}
</script>
<style>
</style>
j-leaflet 源码
<template>
<view :data="data" :change:data="leaflet.addMarker" :location="location" :change:location="leaflet.center"
class="map" id="map"></view>
</template>
<script>
export default {
props: {
data: Array,
location: Object
},
methods: {
changeView(options) {
this.$emit('changeView', options)
},
}
}
</script>
<script module="leaflet" lang="renderjs">
import L from 'static/js/leaflet.js';
export default {
data() {
return {
map: null,
marker: {}
};
},
mounted() {
this.initMap()
},
methods: {
// 鍒濆鍖栧湴鍥?
initMap() {
this.map = L.map('map', {
// crs: L.CRS.EPSG3857,
center: [23.180695, 113.412674],
zoom: 17,
minZoom: 5,
maxZoom: 18,
dragging: true,
attributionControl: false,
zoomControl: false
});
// 娣诲姞鍥惧眰
L.tileLayer(
'http://t0.tianditu.gov.cn/vec_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=vec&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的秘钥', {
zoomControl: true
}).addTo(this.map);
L.tileLayer(
'http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=你的秘钥', {
zoomControl: true
}).addTo(this.map);
this.mapEvent()
},
mapEvent() {
this.map.on('zoomend', (a, b) => {
let view = this.getBounds()
// 主动传递 等价于 $emit
UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
cid: this._$id,
method: 'changeView',
args: view
})
console.log(24)
})
this.map.on('moveend', (a, b) => {
let view = this.getBounds()
// 主动传递 等价于 $emit
UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
cid: this._$id,
method: 'changeView',
args: view
})
console.log(25)
})
},
//可视范围 获取
getBounds() {
//左下
let west = this.map.getBounds().getSouthWest()
var leftdown = [west.lat, west.lng];
//左上
let northWest = this.map.getBounds().getNorthWest()
var leftup = [northWest.lat, northWest.lng];
//右上
let orthEast = this.map.getBounds().getNorthEast()
var rightup = [orthEast.lat, orthEast.lng];
//右下
let southEast = this.map.getBounds().getSouthEast()
var rightdown = [southEast.lat, southEast.lng];
return {
leftup,
leftdown,
rightup,
rightdown
}
},
center(point) {
// 添加中心点,并且移动到地图至中心点
if (!point || !point.latitude || !point.longitude) return
if (!this.marker.center) {
let m = L.marker([point.latitude, point.longitude], {
icon: L.divIcon({
className: 'div-icon'
})
}).addTo(this.map)
this.marker.center = m
} else {
this.marker.center.setLatLng([point.latitude, point.longitude])
}
this.map.panTo({
lng: point.longitude,
lat: point.latitude
});
},
addMarker(points) {
// 获取到数据,进行处理,可以是添加标记,也可以是其他处理
}
}
}
</script>
<style lang="scss">
.map {
width: 100%;
top: 0;
bottom: 0;
position: absolute;
z-index: 0;
}
</style>
注意事项
- 使用leaflet插件对天地图的底图进行渲染,与uni.getLocation 中使用的三方地图的sdk互不相干,是两个独立的东西。
- 在打不同平台的包时,需要在manifest.json配置不同的地图key。
- 安卓包需要去对应的地图平台申请安卓使用的key。ios包申请ios使用的 key。
- 在通信时需要注意对象深浅拷贝问题,最好都是深拷贝,浅拷贝容易发生异常。
- 云打包每天打包都有固定次数,推荐使用模拟器查看效果。