原因

在开发中有个需求,要统计用户在每个页面的访问量,和停留时间。这个在Vue项目中很好实现,利用全局路由,在router的beforeEach方法和afterEach方法中做事情就可以了。

但小程序中没有全局路由,又不想在每个页面的onShow和onHide中写重复代码,该怎么实现呢?

解决方案

先说明这个解决方案没有完美的解决,还是有些问题,有部分问题没法解决。

方法就是重写微信的三个方法,wx.navigateTo,wx.switchTab,wx.navigateBack,这三个方法分别对应跳转页面、切换tab、返回上一页三个功能,在这三个方法中调用后端接口,记录访问日志。

首先是重写wx.navigateTo方法,因为该方法接收一个url参数,而url可能是 / 开头, ./ 开头, ../开头,还需要去掉url上的参数,需要做一些处理。

function rewriteNavigateTo() {
  let oldNavigateTo = wx.navigateTo
  wx.navigateTo = function(obj) {
    let pages = getCurrentPages()
    // pages为空则不做处理
    if (pages.length === 0) {
      oldNavigateTo(obj)
      return
    }
    let leavePath = pages[pages.length - 1].__route__
    // 拼接跳转路径
    let enterPath = obj.url
    // 去除.html
    if (enterPath.indexOf('.html') != -1) {
      enterPath = enterPath.substr(0, obj.url.indexOf('.html'))
    }
    // 去除链接参数
    if (enterPath.indexOf('?') != -1) {
      enterPath = enterPath.substr(0, obj.url.indexOf('?'))
    }
    // 去除 ../../
    let tempPath = leavePath
    tempPath = tempPath.substr(0, tempPath.lastIndexOf('/') + 1)
    while (true) {
      if (enterPath.startsWith('../')) {
        enterPath = enterPath.substr(3)
        tempPath = tempPath.substr(0, tempPath.length - 1)
        tempPath = tempPath.substr(0, tempPath.lastIndexOf('/') + 1)
      } else {
        break
      }
    }
    // 去除 ./
    if (enterPath.startsWith('./')) {
      enterPath = enterPath.substr(2)
    }
    // /开头
    if (enterPath.startsWith('/')) {
      tempPath = ''
    }
    enterPath = tempPath + enterPath

    obj.success = function(res) {
      //进入新页面记录日志
      enterPageLog(enterPath)
    }
    //跳转
    oldNavigateTo(obj)
  }
}

重写wx.switchTab方法

function rewriteSwitchTab() {
  let oldSwitchTab = wx.switchTab
  wx.switchTab = function(obj) {
    let pages = getCurrentPages()
    let leavePath = ''
    if(pages.length>0){
      leavePath = pages[pages.length - 1].__route__
    }
    //离开页面记录日志
    if (!tabPathSet.has(leavePath)) {
      leavePageLog(leavePath)
    }
    //跳转
    oldSwitchTab(obj)
  }
}

最后是重写wx.navigateBack方法

function rewriteNavigateBack() {
  let oldNavigateBack = wx.navigateBack
  wx.navigateBack = function(obj) {
    let pages = getCurrentPages()
    let leavePath = pages[pages.length - 1].__route__
    let enterPath
    if (obj.delta) {
      enterPath = pages[pages.length - 1 - obj.delta].__route__
    } else {
      enterPath = pages[pages.length - 2].__route__
    }
    leavePageLog(leavePath)
    obj.success = function(res) {
      //进入新页面记录日志
      enterPageLog(enterPath)
    }
    oldNavigateBack(obj)
  }
}

结论

本篇只是记录日志,当然也可以在重写的方法wx.navigateTo或wx.switchTab中判断权限,权限不够则不跳转,或跳转到登录完善信息页。

这样大致实现了类似Vue的全局路由,但还是有几个问题

  1. 点击微信小程序底部的tab不会触发上面任何的方法,也无法监控,需要在tab页的onShow和onHide手动记录日志
  2. 安卓手机的物理返回键没法监控,不会触发wx.navigateBack方法

那有没有更好的方案呢,答案是有,下一期说