微信小程序开发——点击防重的解决方案

对于一些涉及后端接口请求的单击事件,不论后端是否做了请求限制,前端还是有必要进行点击防重处理的。

这样既能减少对服务器端的压力,也能有效防止因重复请求而造成一些不可预期的异常。

尤其是接口请求结果处理的逻辑中有需要调用小程序api,如获取手机号码授权、支付、领取卡券这些API。

虽然这些API都能调起自己的原生界面,但是从请求到相关原生界面展示出来之前是会有一定的时间的,如果在这个空档用户快速点击,那么就会造成接口被重复请求,直接回影响到小程序API的调用。

对于点击防重,以前用过一种比较笨的方法,就是自定义loading组件,在接口请求开始前loading,API调用complete回调中隐藏loading。

自定义loading组件点击防重:

之所以自定义loading,是由于小程序的showToast和showLoading只能显示一个,为了避免showToast的影响,我们需要自定义一个loading组件;

loading组件需要有蒙板,这样loading的时候能隔离页面,有效的屏蔽点击(蒙板可以设置一个蒙板是否透明的参数,正常调用显示半透明灰底蒙板,涉及到小程序API不需要灰底蒙板的就显示透明蒙板)。

当然,这种做法只不过是避免showToast影响showLoading的同时,还可以做点击防重,如果仅仅是点击防重,这代码量就比较多了。

如果原生的loading就能满足需求,那么可以采用下面的方法进行点击防重:

定义点击标志变量进行点击防重:

Page({
  data: {
    ......
    isclick: false, //点击防重标志
  },
  /**
   * 需要做防点击防重的单击事件
   */
  onclick: function() {
    var self = this
    if(!self.data.isclick){
      self.setData({
        isclick:true
      })
      setTimeout(function () {
        self.setData({
          isclick: false
        })
      }, 500);
    }else{
      return;
    }
    ......
  }
   ......
})

这种方法,就简单多了。这里采用了定时器放开点击状态,非特殊情况,500ms后放开点击状态也足够用了,也不会对用户体验造成影响。

当然,如果你不想这么做,可以在指定接口调用成功之后或某些操作完成后再放开点击状态,但有风险的地方就在于如果这个过程中一个地方出问题,那么很可能这个单击事件已经被锁定而无法放开了,用户重试的机会都没有,所以这种方法慎用。

对于上边的代码,如果需要用到的地方比较多,可以封装到公共方法文件中:

//util.js

//点击防重
let isClick=false;
let preventDuplicateClicks=function(){
  if (!isClick) {
    isClick=true    
    setTimeout(function () {
      isClick = false
    }, 500);
    return false;
  } else {
    return true;
  }
}
module.exports = {
  preventDuplicateClicks: preventDuplicateClicks
}

方法调用:

import utils from '../../utils/util.js'
Page({
  ......
  /**
   * 1.需要防重的单击事件
   */
  orderPay: function() {
    var self = this
    if(utils.preventDuplicateClicks()) return;
    ......
  },
  ......
})

上边代码并没有处理多个单击事件的冲突问题,毕竟是同一个标志变量。但是一般情况下,用户连续点击两个按钮的时间已经超过500ms了(有意测试除外)。如果一定要解决,那么可以用数组来区分不同的单击事件,示例代码如下:

/**
 * 点击防重函数
 * 需要避免冲突的单击事件需要传不同的index参数,如果不传视为不处理冲突,共用一个标志值
 */
let isClick = [];
let preventDuplicateClicks = function(index) {
  if (!index || isNaN(index)) index = 0;
  if (!isClick[index]) {
    isClick[index] = true
    console.log(isClick)
    setTimeout(function() {
      isClick[index] = false
    }, 1000);
    return false;
  } else {
    return true;
  }
}
...
module.exports = {
  preventDuplicateClicks
}

调用方法:

//不处理冲突
if (utils.preventDuplicateClicks()) return;

//处理冲突
if (utils.preventDuplicateClicks(1)) return;

这样的话,只要不同的单击事件传的参数不同,那么不同单击事件的点击防重就不会冲突。

注意:

1.点击防重对单击事件锁定的时间一般半分钟足够了,如果涉及到小程序API调用,如支付、领取卡券类的API,调起API相应页面的时间一般都会有点久(大于500ms),可以把这个值设置成1000ms,对用户体验不会有影响的,毕竟微信支付、领取卡券之类的界面加载出来没那么快,用户基本上感觉不到我们点击防重的。

2.如果有需要,给 preventDuplicateClicks 方法再增加一个锁定时间的参数,这样使用起来更灵活,可以满足不同需求。

posted on 2019-04-24 19:07  逍遥云天  阅读(3112)  评论(3编辑  收藏  举报

导航