最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

教你用Uniapp實(shí)現(xiàn)微信小程序的GPS定位打卡

 更新時(shí)間:2022年11月17日 11:16:33   作者:橙某人  
地圖組件用于展示地圖,而定位API只是獲取坐標(biāo),請(qǐng)勿混淆兩者,下面這篇文章主要給大家介紹了關(guān)于如何使用Uniapp實(shí)現(xiàn)微信小程序的GPS定位打卡的相關(guān)資料,需要的朋友可以參考下

寫(xiě)在開(kāi)頭

哈嘍,隔了幾天沒(méi)寫(xiě)文章,小編又回來(lái)了(?ω?)。最近接了一個(gè)校園的需求,主要功能是希望學(xué)生每天進(jìn)行定位打卡,幫助班導(dǎo)確認(rèn)學(xué)生是否在校的情況。

上面圖片是大致的交互過(guò)程,定位打卡是個(gè)比較常見(jiàn)的功能了,只是很多時(shí)候都是在 APP 上完成的,這次需求方是希望專(zhuān)門(mén)做個(gè)小程序來(lái)使用,當(dāng)然,整個(gè)小程序還有其他很多功能模塊,本章我們先來(lái)分享一下定位打卡功能,前端具體需要做哪些事情。

開(kāi)通相關(guān)API權(quán)限

首先,因?yàn)檫@次定位打卡功能使用的是 GPS 來(lái)定位的,這就需要獲取用戶(hù)的地理位置信息。在小程序中,要獲取用戶(hù)的地理位置,微信官方提供了部分 API ,但是這些 API 有權(quán)限要求,我們需要先登陸 小程序后臺(tái) 去申請(qǐng)。

登陸后,按路徑「開(kāi)發(fā)」-「開(kāi)發(fā)管理」-「接口設(shè)置」中找到相關(guān) API ,填寫(xiě)你使用 API 的理由,提交申請(qǐng)即可。

本次的功能小編一共會(huì)使用到了以下兩個(gè) API

  • wx.chooseLocation:用于打開(kāi)微信小程序自帶的地圖,能選擇一個(gè)位置,獲取目標(biāo)位置的經(jīng)緯度。
  • wx.getLocation:用于獲取用戶(hù)當(dāng)前所在的地理位置信息,主要為了拿到經(jīng)緯度;不過(guò),這個(gè) API 有點(diǎn)難申請(qǐng)通過(guò),小編也是申請(qǐng)了三次才過(guò)的,真是挺麻煩-.-,好像一般小程序主體是政府、學(xué)?;蛘叽笃髽I(yè)等機(jī)構(gòu)就比較容易通過(guò)(●—●)。

API 權(quán)限申請(qǐng)好了后,我們就能進(jìn)入正題了,開(kāi)始正式的編碼工作。

項(xiàng)目初始化

項(xiàng)目小編直接使用 uniappHBuilderX 工具創(chuàng)建的,并使用了@dcloudio/uni-ui 作為 UI 庫(kù)。

定位打卡功能的具體交互過(guò)程很簡(jiǎn)單,先由管理人員選取學(xué)校的位置,獲取到學(xué)校經(jīng)緯度信息保存起來(lái),然后學(xué)生每次打卡也會(huì)獲取經(jīng)緯度坐標(biāo),然后計(jì)算兩個(gè)經(jīng)緯度坐標(biāo)的距離,就能推算出學(xué)生是否在校了。

API 配置聲明

項(xiàng)目初始化后,我們還需要進(jìn)行一步很關(guān)鍵的配置聲明,在項(xiàng)目的根目錄下,找到 manifest.json 文件,進(jìn)行如下配置:

{
  ...
  "mp-weixin": {
    "appid": "",
    "setting": {
      "urlCheck": false
    },
    "usingComponents": true,
    "permission": {
      "scope.userLocation": {
        "desc": "測(cè)試-"
      }
    },
    "requiredPrivateInfos": ["getLocation", "chooseLocation"]
  },
  ...
}

主要是 requiredPrivateInfos 字段的配置,至于為什么可以看看官方說(shuō)明,傳送門(mén) 。

選取學(xué)校位置

那么,接下來(lái)進(jìn)行我們的第一步,選取學(xué)校的位置,代碼比較簡(jiǎn)單,直接來(lái)看:

<template>
  <view>
    <uni-section title="學(xué)校" type="line">
      <uni-card title="選點(diǎn)">
        <button @tap="chooseLocation">請(qǐng)?jiān)诘貓D中選擇學(xué)校的位置</button>
        <view v-if="isChooseTarget" class="info">
          <view>{{ schoolInfo.address }}</view>
          <view>{{ `(${schoolInfo.latitude},${schoolInfo.longitude})` }}</view>
        </view>
      </uni-card>
   </uni-section>
  </view>
</template>

<script>
export default {
  data() {
    return {
      schoolInfo: {
        latitude: '',
        longitude: '',
        address: '',
      },
    }
  },
  computed: {
    isChooseTarget() {
      return this.schoolInfo.latitude && this.schoolInfo.longitude
    },
  },
  methods: {
    // 選點(diǎn)
    chooseLocation() {
      uni.chooseLocation({
        success: res => {
          this.schoolInfo.latitude = res.latitude;
          this.schoolInfo.longitude = res.longitude;
          this.schoolInfo.address = res.address;
        }
      });
    },
  }
}
</script>

<style>
.info{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  margin-top: 20rpx;
}
</style>

獲取用戶(hù)的地理位置信息

搞定完學(xué)校的位置后,接下來(lái)就要來(lái)獲取學(xué)生的地理位置了,主要是使用 wx.chooseLocation 來(lái)獲取。

不過(guò),因?yàn)檫@個(gè) API 初次調(diào)用時(shí),會(huì)有一個(gè)主動(dòng)詢(xún)問(wèn)動(dòng)作。

如果你選擇允許授權(quán),那么后續(xù)你可以直接調(diào)用該 API,但是如果選擇拒絕,那么調(diào)用該 API 就會(huì)直接進(jìn)入錯(cuò)誤的回調(diào),并不會(huì)有再次主動(dòng)詢(xún)問(wèn)的動(dòng)作。

那么我們要如何重新授權(quán)呢?總不能拒絕后就不能使用了吧?

也就因?yàn)檫@么一個(gè)行為,我們還會(huì)牽扯出好幾個(gè)權(quán)限相關(guān)的 API,才能完成整個(gè)權(quán)限的閉環(huán)操作。

  • wx.getSetting:獲取用戶(hù)的當(dāng)前設(shè)置。
  • wx.openSetting:調(diào)起用戶(hù)的設(shè)置界面。
  • wx.authorize:提前向用戶(hù)發(fā)起授權(quán)請(qǐng)求。

上面小編簡(jiǎn)單注釋了每個(gè) API 的作用,詳細(xì)信息還是要參考官方文檔為準(zhǔn)。

然后,為了更好的組織代碼,小編把權(quán)限這塊相關(guān)的進(jìn)行簡(jiǎn)單的封裝,新建 /utils/location.js 文件:

/**
 * 獲取是否授權(quán)了定位權(quán)限
 * @param { Boolean } launchAuth: 是否發(fā)起授權(quán)請(qǐng)求, 初次有效
 * @return { Boolean }
 */
export function getLocationAuth(launchAuth) {
  return new Promise(resolve => {
    uni.getSetting({
      success: res => {
        if(launchAuth && res.authSetting['scope.userLocation'] === undefined) {
          return uni.authorize({
            scope: 'scope.userLocation',
            success: () => {
              resolve(true);
            },
            fail: () => {
              resolve(false);
            }
          })
        }
         resolve(res.authSetting['scope.userLocation']);
      },
      fail: err => {
        console.err(err);
      }
    })
  })
}

具體的使用:

<template>
  <view>
    ...
    <uni-section v-if="isChooseTarget" title="學(xué)生" type="line">
     <uni-card title="當(dāng)前位置實(shí)時(shí)信息">
        <template v-slot:title>
          <uni-list>
            <uni-list-item title="當(dāng)前位置實(shí)時(shí)信息">
              <template v-slot:footer v-if="isAuth === 0">
                <text @tap="reGrantAuth" class="text">重新授權(quán)</text>
              </template>
            </uni-list-item>
          </uni-list>
        </template>
        <view class="block">
          <view class="title">經(jīng)緯度:</view>
          <view class="value">
            <text v-if="!loading">{{ jwText || '-' }}</text>
            <view v-else class="loading">
              <uni-icons type="spinner-cycle" size="20"/>
            </view>
          </view>
        </view>
      </uni-card>
    </uni-section>
  </view>
</template>

<script>
import { getLocationAuth } from '@/utils/location';

export default {
  data() {
    return {
      ...,
      loading: false,
      isAuth: -1, // -1: 未授權(quán)  0: 拒絕授權(quán)  1:已授權(quán)
      studentInfo: {
        latitude: '',
        longitude: '',
      },
    }
  },
  computed: {
    ...,
    jwText() {
      const { latitude, longitude } = this.studentInfo;
      if(latitude && longitude) return `(${latitude},${longitude})`;
      return ''
    },
  },
  async onLoad() {
    if(!await getLocationAuth()) {
      this.isAuth = 0;
    }
  },
  methods: {
    chooseLocation() {
      uni.chooseLocation({
        success: async res => {
          ...
          // 判斷是否授權(quán)
          const authRes = await getLocationAuth(true);
          if(authRes) {
            // 獲取用戶(hù)當(dāng)前位置
            this.getLocationInfo();
            this.isAuth = 1;
          }else {
            this.isAuth = 0;
          }
        }
      });
    },
    // 獲取當(dāng)前位置信息
    getLocationInfo() {
      this.loading = true;
      uni.getLocation({
        type: 'gcj02',
        success: ({ latitude, longitude }) => {
          this.studentInfo.latitude = latitude;
          this.studentInfo.longitude = longitude;
          this.loading = false;
        }
      });
    },
    // 重新授權(quán)
    reGrantAuth() {}
  }
}
</script>

<style>
.info{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  margin-top: 20rpx;
}
.block{
  margin-bottom: 20rpx;
}
.title{
  color: #000;
  font-weight: bold;
}
.value{
  width: 100%;
  min-height: 40rpx;
}
.text{
  font-size: 24rpx;
  color: #287DE1;
}
.loading {
  width: 40rpx;
  height: 40rpx;
  transform: rotate(360deg);
  animation: rotation 3s linear infinite;
}
@keyframes rotation{
  0%{
    transform: rotate(0deg);
  }
  100%{
    transform: rotate(360deg);
  }
}
</style>

上面我們成功獲取到用戶(hù)的當(dāng)前位置信息,當(dāng)然,如果用戶(hù)選擇了拒絕,我們也提供了重新授權(quán)的方式。

export default {
  ...,
  methods: {
    ...,
    // 重新授權(quán)
    async reGrantAuth() {
      const authRes = await getLocationAuth();
      if(authRes) {
        uni.showToast({
          title: '已授權(quán)',
          duration: 500,
          icon: 'none'
        });
      }else {
        wx.openSetting({
          success: (res) => {
            if(res.authSetting['scope.userLocation']) {
              this.getLocationInfo();
              this.isAuth = 1;
            }
          },
        })
      }
    },
  }
}

經(jīng)緯度轉(zhuǎn)化成具體地址

上面我們已經(jīng)拿到了學(xué)生用戶(hù)的當(dāng)前經(jīng)緯度坐標(biāo)了,本來(lái)我們接下來(lái)只要計(jì)算兩個(gè)經(jīng)緯度坐標(biāo)之間的距離就能完成功能了,奈何需求方還想要學(xué)生具體位置的中文信息,這就比較麻煩了,唉,但是麻煩也得做,否則沒(méi)飯吃呀-.-。

這個(gè)需求本質(zhì)就是讓我們把經(jīng)緯度轉(zhuǎn)成具體地址,這里需要使用額外的插件來(lái)處理,方式有很多,小編選擇 騰訊的位置服務(wù)

我們直接按照他官網(wǎng)的介紹操作即可。

具體使用:

<template>
  <view>
    ...
    <uni-section v-if="isChooseTarget" title="學(xué)生" type="line">
      <uni-card title="當(dāng)前位置實(shí)時(shí)信息">
        ...
        <view class="block">
          <view class="title">詳細(xì)地址:</view>
          <view class="value">
            <text v-if="!loading">{{ studentInfo.address || '-' }}</text>
            <view v-else class="loading">
              <uni-icons type="spinner-cycle" size="20"/>
            </view>
          </view>
        </view>
       </uni-card>
    </uni-section>
  </view>
</template>

<script>
import { getLocationAuth } from '@/utils/location';
const QQMapWX = require('@/utils/qqmap-wx-jssdk.min.js');

export default {
  data() {
    return {
      ...
      studentInfo: {
        latitude: '',
        longitude: '',
        address: '',
      },
      mapInstance: null,
    }
  },
  computed: { ... },
  async onLoad() {
    this.mapInstance = new QQMapWX({
      key: '你的密鑰',
    });
    if(!await getLocationAuth()) {
      this.isAuth = 0;
    }
  },
  methods: {
    chooseLocation() { ... },
    getLocationInfo() {
      this.loading = true;
      uni.getLocation({
        type: 'gcj02',
        success: ({ latitude, longitude }) => {
          this.studentInfo.latitude = latitude;
          this.studentInfo.longitude = longitude;
          // 經(jīng)緯度轉(zhuǎn)成具體地址
          this.mapInstance.reverseGeocoder({
            location: { latitude, longitude },
            success: res => {
              console.log(res)
              this.studentInfo.address = res.result.formatted_addresses.recommend;
              this.loading = false;
            }
          });
        }
      });
    },
    // 重新授權(quán)
    async reGrantAuth() { ... },
  }
}
</script>

計(jì)算兩個(gè)經(jīng)緯度坐標(biāo)之間的距離

具體位置也搞定后,就剩下最終的功能,計(jì)算兩個(gè)經(jīng)緯度坐標(biāo)之間的距離,這聽(tīng)起來(lái)好像很難,但實(shí)際很簡(jiǎn)單,網(wǎng)上有大把現(xiàn)成的方法,我們直接抄個(gè)來(lái)耍就行了。

/**
 * 根據(jù)經(jīng)緯度獲取兩點(diǎn)距離
 * @param la1 第一個(gè)坐標(biāo)點(diǎn)的緯度 如:24.445676
 * @param lo1 第一個(gè)坐標(biāo)點(diǎn)的經(jīng)度 如:118.082745
 * @param la2 第二個(gè)坐標(biāo)點(diǎn)的緯度
 * @param lo2 第二個(gè)坐標(biāo)點(diǎn)的經(jīng)度
 * @return { Object } { km: 千米/公里, m: 米 }
 * @tips 注意經(jīng)度和緯度參數(shù)別傳反了, 一般經(jīng)度為0~180、緯度為0~90
 */
export function calcDistanceLL(la1, lo1, la2, lo2) {
    let La1 = la1 * Math.PI / 180.0;
    let La2 = la2 * Math.PI / 180.0;
    let La3 = La1 - La2;
    let Lb3 = lo1 * Math.PI / 180.0 - lo2 * Math.PI / 180.0;
    let s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(La3 / 2), 2) + Math.cos(La1) * Math.cos(La2) * Math.pow(Math.sin(
            Lb3 / 2), 2)));
            
    s = s * 6378.137;
    s = Math.round(s * 10000) / 10000;

  return {
    km: s,
    m: Math.round(s * 1000)
  };
}

具體使用:

<template>
  <view>
    ...
    <uni-section v-if="isChooseTarget" title="學(xué)生" type="line">
      <uni-card title="當(dāng)前位置實(shí)時(shí)信息">
        ...
        <view class="block">
          <view class="title">距離學(xué)校距離:</view>
          <view class="value">
            <text v-if="!loading">{{ distanceToText || '-' }}</text>
            <view v-else class="loading">
              <uni-icons type="spinner-cycle" size="20"/>
            </view>
          </view>
        </view>
        <view class="block">
          <view class="title">是否可打卡:</view>
          <view class="value">
            <text v-if="studentInfo.distance > 500 || studentInfo.distance === ''">否</text>
            <view @click="punchClock" v-else class="button yd-flex-h-hC-vC">打卡</view>
          </view>
        </view>
       </uni-card>
    </uni-section>
  </view>
</template>

<script>
import { getLocationAuth, calcDistanceLL } from '@/utils/location';
const QQMapWX = require('@/utils//qqmap-wx-jssdk.min.js');

export default {
  data() {
    return {
      ...
      studentInfo: {
        latitude: '',
        longitude: '',
        address: '',
        distance: '',
      },
      mapInstance: null,
    }
  },
  computed: { 
    distanceToText() {
      if(this.mainInfo.distance !== '') {
        return `${this.mainInfo.distance} 米`;
      }
      return '';
    },
  },
  async onLoad() {
    this.mapInstance = new QQMapWX({
      key: '你的密鑰',
    });
    if(!await getLocationAuth()) {
      this.isAuth = 0;
    }
  },
  methods: {
    punchClock() {
      uni.showToast({
        title: '打卡成功',
        duration: 500,
      });
    },
    chooseLocation() { ... },
    getLocationInfo() {
      this.loading = true;
      uni.getLocation({
        type: 'gcj02',
        success: ({ latitude, longitude }) => {
          this.studentInfo.latitude = latitude;
          this.studentInfo.longitude = longitude;
          // 經(jīng)緯度轉(zhuǎn)成具體地址
          this.mapInstance.reverseGeocoder({
            location: { latitude, longitude },
            success: res => {
              this.studentInfo.address = res.result.formatted_addresses.recommend;
              // 計(jì)算兩個(gè)經(jīng)緯度之間的距離
              const distance = calcDistanceLL(
                this.schoolInfo.latitude,
                this.schoolInfo.longitude,
                latitude,
                longitude,
              );
              this.studentInfo.distance = distance.m;
              this.loading = false;
            }
          });
        }
      });
    },
    // 重新授權(quán)
    async reGrantAuth() { ... },
  }
}
</script>

<style>
...
.button{
  height: 60rpx;
  color: #fff;
  line-height: 1;
  background-color: #287DE1;
  border-radius: 4rpx;
  font-size: 20rpx;
  width: 30%;
  margin: auto;
}
</style>

至此,本篇文章就寫(xiě)完啦,撒花撒花。

總結(jié)

到此這篇關(guān)于用Uniapp實(shí)現(xiàn)微信小程序的GPS定位打卡的文章就介紹到這了,更多相關(guān)Uniapp實(shí)現(xiàn)小程序GPS定位打卡內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • js導(dǎo)出txt示例代碼

    js導(dǎo)出txt示例代碼

    很多新手朋友們都不知道js怎么導(dǎo)出txt,下面有個(gè)不錯(cuò)的示例,大家可以參考下
    2014-01-01
  • js判斷字符長(zhǎng)度以及中英文數(shù)字等

    js判斷字符長(zhǎng)度以及中英文數(shù)字等

    本文為大家介紹下使用js判斷字符長(zhǎng)度及中英文數(shù)字等,下面有個(gè)不錯(cuò)的教程,感興趣的朋友可以參考下
    2013-12-12
  • JavaScript中的ajax功能的概念和示例詳解

    JavaScript中的ajax功能的概念和示例詳解

    AJAX即“Asynchronous Javascript And XML”(異步JavaScript和XML)。這篇文章主要給大家介紹了JavaScript中的ajax功能的概念和示例詳解,感興趣的朋友一起看看吧
    2016-10-10
  • 一文熟練掌握J(rèn)avaScript的switch用法

    一文熟練掌握J(rèn)avaScript的switch用法

    在JavaScript中switch語(yǔ)句是一種用于多條件分支的控制語(yǔ)句,下面這篇文章主要給大家介紹了關(guān)于如果通過(guò)一文熟練掌握J(rèn)avaScript的switch用法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-01-01
  • 微信小程序中如何使用store數(shù)據(jù)共享

    微信小程序中如何使用store數(shù)據(jù)共享

    全局?jǐn)?shù)據(jù)共享?全局?jǐn)?shù)據(jù)共享(狀態(tài)管理)是為了解決組件之間數(shù)據(jù)共享的問(wèn)題,開(kāi)發(fā)中常用的全局?jǐn)?shù)據(jù)共享方案有:Vuex、Redux、MobX等,這篇文章主要介紹了微信小程序中如何使用store數(shù)據(jù)共享,需要的朋友可以參考下
    2023-04-04
  • javascript相等運(yùn)算符與等同運(yùn)算符詳細(xì)介紹

    javascript相等運(yùn)算符與等同運(yùn)算符詳細(xì)介紹

    不管是java、c++、php都有相等運(yùn)算符與等同運(yùn)算符,當(dāng)然javasript也不例外,下面介紹一下
    2013-11-11
  • JavaScript數(shù)組去重算法實(shí)例小結(jié)

    JavaScript數(shù)組去重算法實(shí)例小結(jié)

    這篇文章主要介紹了JavaScript數(shù)組去重算法,結(jié)合實(shí)例形式總結(jié)分析了JavaScript數(shù)組去重相關(guān)的讀寫(xiě)、遍歷、比較、排序等操作及算法改進(jìn)相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2018-05-05
  • 性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議

    性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議

    這篇文章主要介紹了性能優(yōu)化篇之Webpack構(gòu)建速度優(yōu)化的建議,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 使用純javascript實(shí)現(xiàn)放大鏡效果

    使用純javascript實(shí)現(xiàn)放大鏡效果

    本文給大家分享的是使用純javascript實(shí)現(xiàn)放大鏡效果的代碼,并附上封裝的步驟,做電商程序的小伙伴們一定不要錯(cuò)過(guò)。
    2015-03-03
  • JS實(shí)現(xiàn)從對(duì)象獲取對(duì)象中單個(gè)鍵值的方法示例

    JS實(shí)現(xiàn)從對(duì)象獲取對(duì)象中單個(gè)鍵值的方法示例

    這篇文章主要介紹了JS實(shí)現(xiàn)從對(duì)象獲取對(duì)象中單個(gè)鍵值的方法,涉及javascript數(shù)組對(duì)象遍歷、事件監(jiān)聽(tīng)、處理等相關(guān)操作技巧,需要的朋友可以參考下
    2019-06-06

最新評(píng)論

叙永县| 康乐县| 铅山县| 仙游县| 太康县| 大兴区| 扎赉特旗| 岑巩县| 二连浩特市| 永寿县| 宁晋县| 厦门市| 宜兰市| 田东县| 宁南县| 安康市| 平罗县| 平果县| 邵武市| 建瓯市| 白山市| 宁武县| 九龙城区| 商洛市| 含山县| 榆树市| 八宿县| 曲靖市| 新巴尔虎右旗| 华安县| 金昌市| 松原市| 湛江市| 怀柔区| 上饶市| 焉耆| 西畴县| 沈阳市| 安阳县| 霸州市| 左贡县|