基于Vue和uni-app实现前端地图定位与距离测算

一、引言

随着移动互联网的快速发展,地图定位服务在前端应用中的重要性日益凸显。在构建具有位置感知能力的应用中,如何实现准确、高效的地图定位和距离测算成为了技术开发的重点。传统的开发方式在面对复杂的业务场景时,经常面临修改困难、维护成本高等问题。通过组件化开发,我们可以将地图定位与距离测算功能拆分成独立的组件,实现单独开发、单独维护,并与其他组件灵活组合,从而提升开发效率,降低维护成本。

本文将介绍如何基于Vue和uni-app框架实现前端地图定位与距离测算的组件,并探讨其背后的设计原理和实现细节。

效果图如下:

图片

图片

二、技术背景

  1. Vue.js
    Vue.js是一个构建用户界面的渐进式框架,以其简洁的API、灵活的组件系统和高效的性能而广受欢迎。Vue.js允许我们采用自底向上增量开发的设计,可以方便地与其他库或已有项目整合。

  2. uni-app
    uni-app是一个使用Vue.js开发所有前端应用的框架,可以编译到iOS、Android、H5、以及各种小程序(微信/支付宝/百度等)。uni-app提供了丰富的API和组件,使得开发者可以更加便捷地构建跨平台应用。

三、组件设计

  1. 组件功能
    本组件主要实现以下功能:

  • 地图定位:获取用户当前位置信息,并在地图上显示。

  • 目标位置设置:允许用户设置目标位置,并在地图上显示。

  • 距离测算:根据用户当前位置和目标位置,计算并显示两者之间的距离。

  1. 组件结构
    组件结构采用Vue的单文件组件(SFC)形式,包含模板(template)、脚本(script)和样式(style)三个部分。其中,模板部分定义了组件的HTML结构,脚本部分包含组件的逻辑代码,样式部分定义了组件的样式。

  2. 交互方式
    组件间通过props进行数据传递,通过events进行事件通信。例如,父组件可以通过props向地图定位组件传递定位参数,地图定位组件在定位成功后通过events向父组件发送定位结果。

四、实现细节

  1. 地图定位
    使用uni-app提供的地图API进行定位。首先,需要获取用户的定位权限;然后,调用uni.getLocation()方法获取用户当前位置信息;最后,将位置信息传递给地图组件进行显示。

  2. 目标位置设置
    允许用户通过手动输入或选择地图上的点来设置目标位置。对于手动输入方式,可以通过表单组件收集用户输入的位置信息;对于选择地图上的点方式,可以使用uni-app提供的地图选择器组件(uni-map-picker)实现。

  3. 距离测算
    使用Haversine公式计算两点之间的距离。Haversine公式是一种基于经纬度计算地球上两点间大圆距离的公式,具有较高的精度。在计算距离时,需要将经纬度坐标转换为弧度制,并进行相应的数学运算。最后,将计算结果以用户友好的方式进行展示。

使用方法

 App端:manifest.json的“App模块配置”中勾选“Maps(地图)”,并根据项目实际情况勾选使用的三方地图SDK:https://uniapp.dcloud.net.cn/tutorial/app-maps.html#
             H5端:使用地图和定位相关,需要在 manifest.json 内配置腾讯或谷歌等三方地图服务商申请的秘钥(key)。高德地图需要额外配置 securityJsCode 或 serviceHost,

             若是微信小程序只需配置微信小程序权限配置):
                  page.json配置以下

                  // 权限设置
                  "permission": {
                      "scope.userLocation": {
                          "desc": "您的位置信息将用于该活动签到"
                      }
                  }

<!-- scale缩放级别,取值范围为3-20 longitude:地图中心精度 latitude:地图中心纬度 markers:覆盖物 show-location:是否显示定位-->
            <map class="mapV" :latitude="infoDict.lat" :longitude="infoDict.lon" scale='6' :markers="covers"
                show-location=false>
            </map>
HTML代码部分
<template>
    <view class="content">
        <scroll-view class="scrollV" scroll-y="true">

            <view class="inputView">
                <text class="leftTitle">活动内容</text>
            </view>
            <view class="inputView">
                {{"去清远古龙峡漂流"}}
            </view>

            <view class="inputView">
                <text class="leftTitle">签到须知</text>
            </view>
            <view class="inputView">
                {{'距离活动地10km内可签到成功'}}
            </view>

            <!-- 
             App端:manifest.json的“App模块配置”中勾选“Maps(地图)”,并根据项目实际情况勾选使用的三方地图SDK:https://uniapp.dcloud.net.cn/tutorial/app-maps.html#
             H5端:使用地图和定位相关,需要在 manifest.json 内配置腾讯或谷歌等三方地图服务商申请的秘钥(key)。高德地图需要额外配置 securityJsCode 或 serviceHost,

             若是微信小程序只需配置微信小程序权限配置):
                  page.json配置以下

                  // 权限设置
                  "permission": {
                      "scope.userLocation": {
                          "desc": "您的位置信息将用于该活动签到"
                      }
                  }
             -->
            <!-- scale缩放级别,取值范围为3-20 longitude:地图中心精度 latitude:地图中心纬度 markers:覆盖物 show-location:是否显示定位-->
            <map class="mapV" :latitude="infoDict.lat" :longitude="infoDict.lon" scale='6' :markers="covers"
                show-location=false>
            </map>

        </scroll-view>

        <view class="btnview" @tap="goSignIn">{{'签到' + distanceStr}}</view>

    </view>
</template>
JS代码 (引入组件 填充数据)
<script>
    import Vue from 'vue'

    export default {
        data() {
            return {

                // 覆盖物
                covers: [],

                // 目标经纬度信息
                infoDict: {
                    'lon': '113.17',
                    'lat': '23.8'
                },

                // 我的定位经纬度信息
                myPinInfo: {},

                // 默认距离为负数
                distance: -9999,
                distanceStr: ''
            }
        },

        onShow() {

            // 获取当前位置
            this.getlocation();

        },
        methods: {

            getlocation() {

                let myThis = this;
                console.log('获取位置开始');
                uni.getLocation({
                    type: 'gcj02',
                    success: function(res) {
                        myThis.myPinInfo = res;
                        console.log('当前位置的经度:' + res.longitude);
                        console.log('当前位置的纬度:' + res.latitude);

                        myThis.covers = [{
                                latitude: myThis.infoDict.lat,
                                longitude: myThis.infoDict.lon,
                                width: 30,
                                height: 30,
                                id: 20000,
                                iconPath: '../../static/activity_pin.png'
                            },
                            {
                                latitude: myThis.myPinInfo.latitude,
                                longitude: myThis.myPinInfo.longitude,
                                width: 30,
                                height: 30,
                                id: 20001,
                                iconPath: '../../static/people_pin.png'
                            }
                        ];
                        myThis.distance = myThis.getDistance(myThis.infoDict.lat, myThis.infoDict.lon, myThis
                            .myPinInfo.latitude, myThis.myPinInfo.longitude)
                        myThis.distanceStr = '(当前距离' + myThis.distance + '米)';

                    }
                });
            },
            // 计算两点距离
            getDistance(lat1, lng1, lat2, lng2) {
                let EARTH_RADIUS = 6378.137;
                let radLat1 = this.rad(lat1);
                let radLat2 = this.rad(lat2);
                let a = radLat1 - radLat2;
                let b = this.rad(lng1) - this.rad(lng2);
                let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) +
                    Math.cos(radLat1) * Math.cos(radLat2) *
                    Math.pow(Math.sin(b / 2), 2)));
                s = s * EARTH_RADIUS;
                //s = Math.round(s * 10000d) / 10000d;
                s = Math.round(s * 10000) / 10000;
                s = s * 1000; //乘以1000是换算成米
                return s;
            },
            // 弧度计算
            rad(d) {
                return d * Math.PI / 180.0;
            },

            // 立即签到
            goSignIn(e) {

                if (this.distance > 10000) {

                    uni.showModal({
                        title: '温馨提示',
                        content: '您的当前位置距离活动目的地太远, 无法签到',
                        showCancel: false
                    })
                    return;
                } else if (this.distance < 0) {

                    uni.showModal({
                        title: '温馨提示',
                        content: '您的定位权限未打开, 请点击小程序右上角···菜单按钮, 然后点击设置,打开定位权限',
                        showCancel: false
                    })

                    return
                }

            },

        }
    }
</script>
CSS
<style>
    .content {
        display: flex;
        flex-direction: column;
        height: 100%;

    }

    .scrollV {

        width: 100vw;

    }

    .mapV {

        width: calc(100vw);
        height: 320px;
        margin-top: 14px;
    }

    .leftTitle {
        width: 284px;
        height: 44px;
        line-height: 44px;
        font-size: 14px;
        color: #333333;

    }

    .inputView {
        flex-direction: row;
        display: flex;
        height: auto;
        align-items: center;
        margin-left: 13px;
        width: calc(100vw - 30px);
        padding: 2px 0px;
        font-size: 13px;
        color: #666666;

    }

    .btnview {
        display: flex;
        background-color: #FF731E;
        justify-content: center;
        align-items: center;
        color: #ffffff;
        width: 100%;
        height: 50px;
        margin-top: 20px;
    }
</style>

五、总结与展望

本文介绍了基于Vue和uni-app实现前端地图定位与距离测算的组件。通过组件化开发方式,我们将地图定位与距离测算功能拆分成独立的组件,实现了单独开发、单独维护,并与其他组件灵活组合。这不仅提高了开发效率,还降低了维护成本。未来,我们将进一步优化组件的性能和用户体验,并探索更多基于地图的应用场景。

前端技术交流群:

图片

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端组件开发

你的钟意将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值