小程序实例回顾分析--地图组件(上)

功能描述:

  • 1.需要包含定位当前手机
  • 2.根据当前手机位置请求附近车子列表
  • 3.点击车子进行线路规划
  • 4.点击用车进行扫码开锁
  • 5.开锁后地图界面显示骑行时间及重新开锁按钮,可以重新开锁
  • 6.结束用车

整体描述

整体跟摩拜单车/ofo等扫车小程序一样,只是摩拜小程序目前下线了规划路线的功能,具体原因未知。

小程序的地图,是内置的,所以层级不受z-index的影响。所以如果要在地图组件map上覆盖窗口,则需要用 cover-view,cover-image。虽然cover-view和view很相似,但是事实证明, 腾讯还没能把cover-view处理的和view一样,很多view的属性,在cover-view中都会有问题。

一:初始化页面处理

页面初始化时,要初始化地图,对用户进行定位,还需要判断是否能拿到用户id,如果有用户id,则需要进一步请求后台,判断用户当前对骑行状态。

  • 初始化地图:

    地图是一个内置控件,使用需要创建地图对象,然后在对这个对象进行配置。

          // 创建地图对象
            this.mapCtx = wx.createMapContext('map')
    
          // 使用地图对象
          _this.mapCtx.getCenterLocation({
              success: function(res){
                  if ((_this.data.longitude !== res.longitude) || (_this.data.latitude !== res.latitude)){
                      _this.data.longitude = res.longitude
                      _this.data.latitude = res.latitude
                      _this.getPositionList()
                  }
              },
              complete: function (res) {
                  console.log("获取中心点坐标完成");
                  _this.data.timer3 = null
              }
          })
        
  • 获取用户定位:

    这里处理获取到当前位置,然后在markers中添加上标记当前位置的图标,然后去请求位置周围的车辆列表。

            wx.getLocation({
                success: function (res) {
                    if (res && res.longitude) {
                        _this.data.longitude = app.globalData.location.longitude = _this.data.geoLongitude = res.longitude
                        _this.data.latitude = app.globalData.location.latitude =  _this.data.geoLatitude = res.latitude
                        // markers = []
                        markers.push({
                            id: 0,
                            longitude: res.longitude,
                            latitude: res.latitude,
                            iconPath: '../../images/icons/icon-position.png',
                            width: 24,
                            height: 39,
                        })
                        _this.setData({
                            longitude: res.longitude,
                            latitude: res.latitude,
                            markers: markers
                        })
                        _this.getPositionList()
                    }
                },
                fail: function (res) {
                    _this.setData({
                        geoCount: 0
                    })
                }
            })
        
  • 获取用户id:

    用户id是存在本地存储的。这里是获取存储中是否存在用户id

          app.globalData.userInfo.userid = wx.getStorageSync('userid')
        
  • 获取当前骑行状态:

    用户骑行状态有两个方案,一个是用本地数据,一个是直接请求用户状态。

    • 小程序对本地数据,虽然用户是没办法手动清理对,但是直接删除小程序,然后再搜索进入,同样会清理掉本地数据。所以不可能直接使用本地数据。
    • 直接请求用户状态,这是最稳妥对方法,但弊端就是每次都需要去请求数据。因为客户但服务人群是景区游客,车辆放置点信号可能没问题,但用户骑行到景区内部,可能就存在网络不好的情况,所以请求骑行状态也存在一定问题。 因为小程序有一个重新开锁功能,如果信号不好,可以直接进入骑行中状态的时候,可以通过重新开锁用蓝牙打开锁,从而绕过网络问题。
    • 两种方案结合处理:我的思路是,应该先请求用户状态,如果成功返回,就用返回的状态,并更新存储。如果网络错误,则调用存储中的状态。这样,在网络顺畅的情况下,是不会有问题的,因为用的就是接口的数据。 在网络不畅的情况下,虽然有一定的几率出现问题,但能保证绝大部分情况下正常使用重新开锁功能。

    当然,最后因为蓝牙开锁功能还未完善,目前第一个版本先使用但是方案2。

二:请求车辆列表数据

这一步逻辑很简单,移动屏幕,根据地图控件的回调方法,调用请求列表的接口,拿到返回数据,插入到markers中。

但是,小程序的地图组件确实有很多不完善的地方,比如这里的实现。小程序之后bindregionchange:视野发生变化时触发。但是在2.2.5中,并不存在触发方式,只有一个start和一个end,就是不管是 放大缩小,还是拖拽,都会触发这个方法,并且没有提供任何判断依据。

下图文档中所描述的,在2.3中返回了操作方式,但是根据开发工具显示的比例。小于2.3的版本比例仍有7%,如果不能忽略这部分用户,那这个操作方式目前是没办法使用的。

即便能用,还有一个问题。在放大缩小触发bindregionchange时,并没有返回回来当前的sacle。这就让人很难处理根据不同scale层级处理不同显示方式的业务逻辑。

所以这里就需要自己控制好请求的时机了。我的主要思路有下面几点:

  • 1.单次拖动,只在拖动结束时去请求:这个好理解,因为从用户习惯上将,我们肯定是拖到最后中心点到了客户预期的位置,才会松手。
  • 2.请求返回前,不去触发第二次请求,保持"单线程"进行。因为拖动存在一定随意性,如果每次拖动都去异步请求,会有并发请求的可能。因为返回数据要进行 排重处理并交互渲染到地图,而小程序的地图组件会在同一时间多次大量重置markers的时候出现卡顿。所以我认为"单线程"请求是合理的。

这里我当时我在这一步出现了一个问题:拖动结束后,我要获取当前中心点位置,然后添加到请求车辆列表的参数中。在初始化地图的时候,我有longitud和latitude两个 变量来规定地图初始化的时候中心点的位置。这时候我就在得到拖动后中心点位置之后将这两个变量重新赋值,并请求后台接口。但是在拖动的过程中,总是会出现地图一闪一闪的 问题。后来经过费力的排查,才发现我用的是:
    _this.setData({
        longitude: res.longitude,
        latitude: res.latitude,
    })
  

水能载舟亦能覆舟。这里用setData,改变变量值的同时,也触发更新视图。所以会出现闪烁的情况。这时候就要用直接赋值的方式了。引以为戒。

随机浏览