【微信小程序开发】【源码学习】基于微信小程序的地图获取地点信息

源码来源

微信小程序地图获取地点信息(打卡签到功能为例)-2020-7-26
十分感谢作者能将代码分享出来让我们学习参考,如有侵权联系删除

准备工作

前提是要了解腾讯位置服务获取自己的key并且配置在项目中,可以看这篇文章来进行配置
【微信小程序开发】微信小程序集成腾讯位置项目配置

js源码解析

wxmlwxss的代码这里暂且就不做解析了,主要是功能实现的解析

一、require分析

在这里插入图片描述
这里作者一共在Pagerequire了这些数据,其中

  • util常量是作者自己写的一些工具方法,主要是对时间的处理
  • app常量是获取app.js中的数据,为了让qqmapsdk来获取app.js中数据来进行核心业务逻辑的实现
  • urlList是作者用工具类配置向后台请求数据的部分代码
  • qqmapsdk是实例化API的核心类
// location_check_in/location_check_in.js
const util = require('../../utils/util')

// getAPP()相当于获得app.js中的数据
const app = getApp()

// 发送wx.request请求
const urlList = require("../../utils/api.js")  // 根据实际项目自己配置

// 实例化API核心类
// 相当于从app.js 中拿到 globalData 中的 qqmapsdk
const qqmapsdk = app.globalData.qqmapsdk

二、Page页面逻辑分析

在这里插入图片描述
这里每一个方法上都给出了注释,我这里就不一一赘述了,主要是每个方法的具体实现

1.data

正常代码阅读逻辑应该是先从生命周期函数onLoad读起,碰到变量后再去data中查看对应的意思,但是对于写文章来说会逻辑过于混乱,所以我们这里直接吧data中的每个变量的含义进行解析
在这里插入图片描述
一共有这些数据,下面我们来一一剖析一下

  • markers,这个变量主要是用于我们后续getAddress中获取当前地址信息的作用,其中的每个数据我都给出了注释解释
  • poi,就是单纯地存储getAddress中的经纬度信息
  • addressName,是获取当前位置的名称
  • time,是获取当前时间,用于前端显示,只显示时分秒
  • timer,适用于存储每秒调用setINterval获取时间这个方法的返回值,用于程序结束后停止运行这个方法,以免浪费空间
  • timer2,与timer同理,不过这个是每20秒重新获取地址信息的setINterval
  • canClick,主要用于防止用户多次点击签到,让用户只能签到一次
data: {

    // markers:    也就是getAddress中的msk
    // 获取当前地点的
        // 地名 title
        // 经度 longitude
        // 维度 latitude
        // 当前所在位置显示的图标路径   iconPath
        // 图片的宽高? width   height
    markers: '',
    // poi:     也就是位置的经纬度(没有给定位置默认为当前位置)
    poi: {
      latitude: '',
      longitude: ''
    },
    // 当前地点的地点名
    addressName: '',
    // time是获取当前时间 只取时分秒
    time: '',
    // 是setInterval的返回值
    // 返回的值是当前setInterval的id
    // 为什么要返回这个值呢?因为有的时候要涉及到clearInterval,clearInterval(id)就能删除相应的setInterval了
    // 每秒获取时间的setInterval的id
    timer: '',
    // 同上,只不过是每20秒获取一次当前的定位信息的setInterval的id
    timer2: '',  // 用来每个一段时间自动刷新一次定位
    // 允许用户点击,防止多次提交
    // 在checkIn函数中,代表签到只能进行一次
    canClick: true
  },

2.onLoad

在这里插入图片描述

我们可以看到,页面打开主要干了三件事

  • 调用了getTime方法
  • 调用了getAddress方法
  • canClick参数变为ture,代表用户可以点击签到按钮,并且每20秒重新调用一次getAddress方法,来对当前定位进行刷新
//   页面打开时发生
  onLoad: function (options) {
    var that = this
    that.getTime()
    that.getAddress()
    that.setData({
      canClick: true, // 允许用户点击,防止多次提交
      timer2: setInterval(function () {
        that.getAddress()
      }, 20000)  // 每20秒刷新一次定位
    })
  },

3.getTime方法

既然页面第一个加载就是getTime方法,我们就来看一下获取时间这个方法具体是干什么,如何实现的
在这里插入图片描述
每一步都给出了比较详细的解释,这里需要说的一共有两个点

  • 调用了util工具类中的formatDate方法
  • time: time.substr(-8),这个主要是formatDate方法获得的是年月日时分秒,我们只需要时分秒,相当于字符串前八位年月日我们省略了
// 获取时间
  getTime: function () {
    let that = this
    // 设置一个临时变量time等于data内的time
    let time = that.data.time
    that.setData({
      // setInterval是一个实现定时调用的函数,可按照指定的周期(以毫秒计)来调用函数或计算表达式
      // 本函数1000毫秒(1秒)调用一次
      timer: setInterval(function () {

        // 获取当前时间
        // 格式为
        // 2023/05/02 15:18:41
        time = util.formatTime(new Date())
        
        that.setData({
          // 相当于只取时分秒,不取年月日
          // 格式为
          // 15:24:01
          time: time.substr(-8)
        });
        if (time == 0) {
          // 页面跳转后,要把定时器清空掉,免得浪费性能
          // clearInterval()函数是在JavaScript中用于取消setInterval()函数设定的定时执行操作。
          // 相当于把每秒调用的这个函数关掉
          clearInterval(that.data.timer)
        }
      }, 1000)
    })
  },
(1)util工具类中的formatDate方法

在这里插入图片描述

这里没什么理解难点

  • 注意一下ES6语法的箭头表达式
  • 还有最后return中的返回形式,在注释中也有比较详细的解答
  • return中还调用了一个formatNumber
// 这里用到了ES6特性的箭头函数
// 具体可看https://blog.csdn.net/weixin_45709829/article/details/123931582?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522168300966016800222859768%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=168300966016800222859768&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-123931582-null-null.142^v86^insert_down28,239^v2^insert_chatgpt&utm_term=es6%20%E7%AE%AD%E5%A4%B4%E5%87%BD%E6%95%B0&spm=1018.2226.3001.4187
const formatTime = date => {
  // const只能被定义赋值一次,初始化结束后就不能被重新定义或赋值
  const year = date.getFullYear()
  const month = date.getMonth() + 1
  const day = date.getDate()
  const hour = date.getHours()
  const minute = date.getMinutes()
  const second = date.getSeconds()

      // [year,month,day] = [2023,5,2]

    // [year, month, day].map(formatNumber) = ["2023", "05", "02"]

    // [year, month, day].map(formatNumber).join('/') = 2023/05/02

    // [year, month, day].map(formatNumber).join('/') + ' ' = 2023/05/02 (多了一个空格)

    // [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second] = 
    //2023/05/02 15,17,28

    // [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber) = 
    // 2023/05/02 15,18,18

    // [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') = 
    // 2023/05/02 15:18:41
    // 也就是说join相当于把数组中间插入一个特定字符后再变成字符串
    // map相当于补零到两位数

  return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':')
}
(2)util工具类中的formatNumber

在这里插入图片描述
注释中给出了解释

//   用于map,将不是字符串的转化为字符串
// 再将一位的时间补0
// 比如17:3:2 =>17:03:02
const formatNumber = n => {
  n = n.toString()
  return n[1] ? n : '0' + n
}

4.getAddress方法

在这里插入图片描述
在这里插入图片描述
这里是比较长的,但是基本上都是官网给出的模板,主要用到了我们开头常量中qqmapsdk逆地址解析(坐标位置描述)函数
其中官方文档为逆地址解析(坐标位置描述)

//  获取地址
  getAddress(e) {
    var that = this;
    // reverseGeocoder 逆地址解析(坐标位置描述)
    // 详见官方文档https://lbs.qq.com/miniProgram/jsSdk/jsSdkGuide/methodReverseGeocoder
    qqmapsdk.reverseGeocoder({
      //位置坐标,默认获取当前位置,非必须参数
      /**
       * 
        location: {
          latitude: 39.984060,
          longitude: 116.307520
        },
      */
      // 成功后的回调
      success: function(res) {
        // console.log(res);
        that.setData({
          addressName: res.result.address
        })
        var res = res.result;
        var mks = [];
        //当get_poi为0时或者为不填默认值时,检索目标位置,按需使用
        mks.push({ // 获取返回结果,放到mks数组中
          title: res.address,
          id: 0,
        //   维度
          latitude: res.location.lat,
        //   地名
          longitude: res.location.lng,
        //   当前所在位置显示的图标路径
          iconPath: '../../images/zcxj/myPosition.png', // 图标路径
        //   图标的像素?
          width: 21,
          height: 28,
          // callout: { //在markers上展示地址名称,根据需求是否需要
          //   content: res.address,
          //   color: '#000',
          //   display: 'ALWAYS'
          // }
        });
        that.setData({ // 设置markers属性和地图位置poi,将结果在地图展示
          markers: mks,
          poi: {
            latitude: res.location.lat,
            longitude: res.location.lng
          }
        });
      },
      fail: function(error) {
        console.error(error);
      },
      complete: function(res) {
        console.log(res);
      }
    })
  },

5.rePosition方法

在这里插入图片描述
用户在前端主动点击了重新定位,我们这里要调用getAddress重新获取定位

//   用户在前端点击重新定位的按钮,重新请求位置
  rePosition: function () {
    console.log('用户点了重新定位')
    this.getAddress()
  },

6.onUnload方法

在这里插入图片描述
在用户退出时触发,主要用于将两个Interval关闭,以免浪费资源

//   onunload 事件在用户退出页面时发生
  onUnload: function () {
    //   根据timer和timer2存储的id来
    // 清除两个不断循环的setInterval
    clearInterval(this.data.timer)
    clearInterval(this.data.timer2)
    console.log("定时器已被清除")
  },

7.checkIn方法

在这里插入图片描述
用户在前端点击了签到按钮,我们先把canClick设置为FALSE,代表用户点了一次除非签到失败是不能点第二次的,然后获取当前时间以及地点名称,并返回给前端的用户,提示用户检查当前签到时间和地点是否有误,如果有误则将canClick改回true,代表本次签到未成功,用户还可以点击一次签到事件,如果成功,则唤起业务逻辑

//   用户在前端点击了签到按钮
  checkIn: function () {

    // 这里canClick代表签到按钮只能点一次
    this.setData({
      canClick: false
    })
    console.log('用户点击了签到')

    
    var that = this
    // 重新获得当前时间
    var nowTime = util.formatTime(new Date())
    // 展示弹窗
    wx.showModal({
      title: '请确认打卡信息',
      // content: '请确认待整改项已整改完毕!',
      content: `地点:${this.data.addressName}\n时间:${nowTime}`,  // 开发者工具上没有换行,真机调试时会有的
      confirmText: '确认',
      success (res) {
        if (res.confirm) {
          console.log('用户点击确定')
          // 调起签到接口
          that.realyCheckIn()
          
        } else if (res.cancel) {
          console.log('用户点击取消')
          that.setData({
            canClick: true
          })
        }
      }
    })
  },

8.realyCheckIn方法

在这里插入图片描述
因为作者本身逻辑代码的隐私要求以及本人实在没看懂下面的代码,这里就只说到request向后台发送请求的部分,欢迎其他读者进行补充
首先我们要向后端传输数据,需要传递经纬度用户信息签到事件等信息,所以我们将所有信息封装成表单来向后端进行发送

//   签到业务逻辑实现
  realyCheckIn: function() {
    var that = this
    // 其他需要一并提交过去的业务数据
    var patrolForm = app.globalData.patrolForm  

    console.log(app.globalData)
    // debugger
    // 要在这里给 patrolForm 补充其他的参数
    // 补充了当前地点的名称以及当前的时间
    patrolForm.checkaddress = this.data.addressName
    patrolForm.searchtime = util.formatTime(new Date())
    // 应该先判断用户有没有登录,没登录就授权登录
    patrolForm.searchuser = app.globalData.user ? app.globalData.user.UserName : app.globalData.userInfo.nickName
    console.log("传给后台的 searchuser:", patrolForm.searchuser)
    // 拼接:"经度,纬度"
    patrolForm.latandlon = this.data.poi.longitude + "," + this.data.poi.latitude
    

    console.log(patrolForm)
    console.log("↑ 签到提交的post参数")

    var tmpNumber = 0
    // 向后端发送请求
    wx.request({
      url: urlList.submitCheckInInfo,
      data: patrolForm,
      method: "POST",
      header: {
        'content-type': 'application/x-www-form-urlencoded'
      },
      success: function (res) {
        console.log(res)
        // 如果请求成功了
        if(res.data.IsSuccess) {
            // 这里typeof是返回当前 res.data.IsSuccess 的数据类型,比如String Int
          console.log(res.data.IsSuccess, typeof(res.data.IsSuccess))
          console.log("请求成功")
          var patrolId = res.data.ReturnData[0].id
          // // 看怎么取到返回的id
          // debugger

          if (patrolForm.img_arr1.length > 0) {
            for (var i = 0; i < patrolForm.img_arr1.length; i++){
              tmpNumber = i
            //   上传图片
              wx.uploadFile({
                // 图片上传的接口地址
                url: urlList.submitCheckInPhoto + "?patrolid=" + patrolId,
                filePath: patrolForm.img_arr1[i],
                name: 'content',
                // formData: {
                //   // 这里面可以携带一些参数一并传过去
                //   patrolId: patrolId
                // },
                // header: {
                //   Authorization: token
                // },
                success: function (res) {
                  console.log(res)
                },
                fail: function (res) {
                  that.setData({
                    canClick: true
                  })
                },
                complete: function () {
                  // 因为上传图片是异步操作,所以会导致这里的 i 会取不到,故需要用个作用域更大点的变量来标识,否则 if 里面的代码不会执行
                  if(tmpNumber === patrolForm.img_arr1.length - 1) {
                    // 有图片就等图片上传完了再返回首页
                    wx.showToast({
                      title: '巡查签到成功!',
                      icon: 'success',
                      duration: 2000,
                      complete: function(){
                        wx.navigateBack({
                          delta: 2  // 回退两层页面
                        })
                      }
                    })
                  }
                }
              })
            }
          } else{
            wx.showToast({
              title: '巡查签到成功!',
              icon: 'success',
              duration: 2000,
              complete: function(){
                wx.navigateBack({
                  delta: 2
                })
              }
            })
          }
        }
      },
      fail: function(res) {
        that.setData({
          canClick: true
        })
      }
    })

  },
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值