uni-app如何引入天地图并兼容app

uni-app引入天地图打包成app后,兼容安卓。该方式仅兼容安卓、h5,微信小程序需要用到其他方案。

安卓模拟器最终效果

image.png

uni-app提供的<map>组件,仅支持下面的服务商,想使用天地图或其他地图,需要搭配地图引擎使用。


image.png

本案例使用工具与插件

  • 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
  • 放置目录结构


    image.png

引用 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。
  • 在通信时需要注意对象深浅拷贝问题,最好都是深拷贝,浅拷贝容易发生异常。
  • 云打包每天打包都有固定次数,推荐使用模拟器查看效果。
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容