小程序中tab快速切换时的防抖与节流

今天测试在测试小程序时,提了一个bug,真机测试的时候,快速点击tab切换时,会出现下面的swiper-item中的内容快速闪烁,无法停止的情况。想了很久也上网查了大量资料,最后突然想起来好像与防抖和节流有关,于是…在这里插入图片描述
函数防抖:

英文 debounce 有防反跳的意思,大致就是指防止重复触发。

那么,函数防抖,真正的含义是:延迟函数执行。即不管debounce函数触发了多久,只在最后一次触发debounce函数时,才定义setTimeout,到达间隔时间再执行 需要防抖的函数。

用处:多用于 input 框 输入时,显示匹配的输入内容的情况。

函数节流:

 英文 throttle 有节流阀的意思。大致意思也是 节约触发的频率

那么,函数节流,真正的含义是:单位时间n秒内,第一次触发函数并执行,以后 n秒内不管触发多少次,都不执行。直到下一个单位时间n秒,第一次触发函数并执行,这个n秒内不管函数多少次都不执行。

用处:多用于页面scroll滚动,或者窗口resize,或者防止按钮重复点击等情况

在小程序中,函数防抖、函数节流的使用方式:

一般都会把这两种方法封装在公用的 js 中:

tool.js:

/*函数节流*/
function throttle(fn, interval) {
  var enterTime = 0;//触发的时间
  var gapTime = interval || 300 ;//间隔时间,如果interval不传,则默认300ms
  return function() {
    var context = this;
    var backTime = new Date();//第一次函数return即触发的时间
    if (backTime - enterTime > gapTime) {
      fn.call(context,arguments);
      enterTime = backTime;//赋值给第一次触发的时间,这样就保存了第二次触发的时间
    }
  };
}

/*函数防抖*/
function debounce(fn, interval) {
  var timer;
  var gapTime = interval || 1000;//间隔时间,如果interval不传,则默认1000ms
  return function() {
    clearTimeout(timer);
    var context = this;
    var args = arguments;//保存此处的arguments,因为setTimeout是全局的,arguments不是防抖函数需要的。
    timer = setTimeout(function() {
      fn.call(context,args);
    }, gapTime);
  };
}

export default {
  throttle,
  debounce
};

函数节流的说明:

(1) 第一次执行时,是一定能执行函数的。

(2) 然后 n秒内第二次触发的时候,当第一次与第二次间隔不足 设置的间隔时间时,就不会执行。之后第三、第四次触发还是不执行。

(3) 直到 n秒之后 有且仅有一次,并且是第一次再次触发函数。

函数防抖的说明:

(1) 第一次触发函数时,定义了一个定时器。在 n秒后执行。

(2) 然后 函数第二次触发的时候,由于闭包的特性,这时候的 timer已经是第一次触发时的 定时器的标识了。然后直接清除第一次的setTimeout,这时候第一次的setTimeout里面的内容就不会执行了。然后再定义第二次的setTimeout。

(3) 然后重复第二个步骤,一直清除,又一直设置。直到函数最后一次触发,定义了最后的一个定时器,并且间隔 n秒 执行。

(4) 如果在 最后一个定时器没执行时,函数又触发了,那么又重复第三步。相当于 设置的间隔时间,只是延迟函数执行的时间,而不是间隔多少秒再执行。



到这里,这两个方式的区别就很明显了。函数节流是减少函数的触发频率,而函数防抖则是延迟函数执行,并且不管触发多少次都只执行最后一次。

使用:(不知道为什么要写e[0]才行,求解)

import tool from "../../../utils/tool.js";
     /*点击切换*/
  clickTab: tool.throttle(function(e) {
    var _this = this;
    if (this.data.currentTab === e[0].currentTarget.dataset.current) {
      return false
    } else {
      this.setData({
        currentTab: e[0].currentTarget.dataset.current
      })
    }
  }),
/*滑动切换*/
  bindChange(e) {
    var _this = this;
    this.setData({
      currentTab: e.detail.current
    })
  },

下面是完整代码:
html:

<view style='height:20rpx;background:#f0f0f0'></view>
<!-- 选项卡 -->
<view class="swiper-tab">
  <view class="swiper-tab-item {{currentTab==0?'active':''}}" data-current="0" bindtap="clickTab">
    <image wx:if="{{currentTab==0}}" class='image1' src='../../../images/home/guanhuai.png'></image>
    <image wx:else class='image1' src='../../../images/home/guanhuaian.png'></image>
    <text>领导关怀</text>
  </view>
  <view class="swiper-tab-item {{currentTab==1?'active':''}}" data-current="1" bindtap="clickTab">
    <image wx:if="{{currentTab==1}}" class='image2' src='../../../images/home/zhidu.png'></image>
    <image wx:else class='image2' src='../../../images/home/zhiduan.png'></image>
    <text>制度规范</text>
  </view>
  <view class="swiper-tab-item {{currentTab==2?'active':''}}" data-current="2" bindtap="clickTab">
    <image wx:if="{{currentTab==2}}" class='image3' src='../../../images/home/gonggao.png'></image>
    <image wx:else class='image3' src='../../../images/home/gonggaoan.png'></image>
    <text>市场公告</text>
  </view>
</view>
<!-- 选项卡内容 -->
<swiper current='{{currentTab}}' duration="{{300}}" style="height:90vh" bindchange="bindChange">
  <swiper-item>
    <block wx:if="{{messageData.length == 0}}">
      <view class='zanwu'>暂无数据</view>
    </block>
    <scroll-view scroll-y="{{true}}" style="height:100%">
      <block wx:for="{{messageData}}" wx:key="{{index}}">
        <view class='message_item space_between' data-item="{{item}}" bindtap='goDetail'>
          <image wx:if='{{item.imgUrl}}' class='item_image' src='{{item.imgUrl}}'></image>
          <image wx:else class='item_image' src='/images/home/zhanwei.png'></image>
          <view class='item_right'>
            <view class='item_title'>{{item.title}}</view>
            <view class='item_date'>{{item.date}}</view>
          </view>
        </view>
      </block>
    </scroll-view>
  </swiper-item>
  <swiper-item>
    <block wx:if="{{messageData2.length == 0}}">
      <view class='zanwu'>暂无数据</view>
    </block>
    <scroll-view scroll-y="{{true}}" style="height:100%">
      <block wx:for="{{messageData2}}" wx:key="{{index}}">
        <view class='message_item space_between' data-item="{{item}}" bindtap='goDetail'>
          <image wx:if='{{item.imgUrl}}' class='item_image' src='{{item.imgUrl}}'></image>
          <image wx:else class='item_image' src='/images/home/zhanwei.png'></image>
          <view class='item_right'>
            <view class='item_title'>{{item.title}}</view>
            <view class='item_date'>{{item.date}}</view>
          </view>
        </view>
      </block>
    </scroll-view>
  </swiper-item>
  <swiper-item>
    <block wx:if="{{messageData3.length == 0}}">
      <view class='zanwu'>暂无数据</view>
    </block>
    <scroll-view scroll-y="{{true}}" style="height:100%">
      <block wx:for="{{messageData3}}" wx:key="{{index}}">
        <view class='message_item space_between' data-item="{{item}}" bindtap='goDetail'>
          <image wx:if='{{item.imgUrl}}' class='item_image' src='{{item.imgUrl}}'></image>
          <image wx:else class='item_image' src='/images/home/zhanwei.png'></image>
          <view class='item_right'>
            <view class='item_title'>{{item.title}}</view>
            <view class='item_date'>{{item.date}}</view>
          </view>
        </view>
      </block>
    </scroll-view>
  </swiper-item>
</swiper>

css:

/* details/home/marketInfo/marketInfo.wxss */

page {
  background: #fff;
}

.swiper-tab {
  width: 100%;
  text-align: center;
  height: 78rpx;
  line-height: 78rpx;
  display: flex;
  flex-flow: row;
  justify-content: space-between;
  background: #f9f9f9;
  margin-top: 10rpx;
}

.swiper-tab-item {
  width: 33.33%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.swiper-tab-item image {
  margin-right: 14rpx;
}

.swiper-tab-item image.image1 {
  width: 29rpx;
  height: 32rpx;
}

.swiper-tab-item image.image2 {
  width: 25rpx;
  height: 31rpx;
}

.swiper-tab-item image.image3 {
  width: 30rpx;
  height: 31rpx;
}

.swiper-tab-item text {
  color: #060606;
  font-size: 30rpx;
  display: inline-block;
  height: 100%;
  position: relative;
}

.swiper-tab-item.active text {
  color: #50b2fa;
  /* border-bottom: 4rpx solid #F65959; */
  font-size: 30rpx;
  font-weight: bold;
}

.swiper-tab-item.active text::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 58rpx;
  height: 3rpx;
  background: linear-gradient(0deg, rgba(29, 188, 229, 1) 0%, rgba(51, 205, 169, 1) 100%);
}

swiper-item {
  width: 100%;
  box-sizing: border-box;
  padding: 24rpx 50rpx;
}

.message_item {
  padding: 28rpx 20rpx;
  background: #f4f4f4;
  margin-bottom: 28rpx;
  border-radius:0px 30rpx 30rpx 0px;
  align-items: center;
}

.item_image {
  width: 135rpx;
  height: 100rpx;
  margin-right: 30rpx;
  border-radius: 10rpx;
}

.item_right {
  width: 445rpx;
}

.item_title {
  font-size: 28rpx;
  height: 80rpx;
  color: #060606;
  /* margin-bottom: 20rpx; */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  overflow: hidden;
  text-overflow: ellipsis;
  -webkit-box-orient: vertical;
}

.item_date{
  font-size:26rpx;
  color: #999999
}
/*暂无数据*/

.zanwu {
  text-align: center;
  color: #b3b3b3;
  margin-top: 20rpx;
  font-size: 26rpx;
}

js:

// details/home/marketInfo/marketInfo.js
import {
  wxRequest
} from "../../../utils/util.js"
import {
  loginCheck
} from "../../../utils/filter.js"
import tool from "../../../utils/tool.js";
Page(loginCheck({

  /**
   * 页面的初始数据
   */
  data: {
    currentTab: 0,
    messageData: [],
    messageData2: [],
    messageData3: [],
  },
  /*点击切换*/
  clickTab: tool.throttle(function(e) {
    var _this = this;
    if (this.data.currentTab === e[0].currentTarget.dataset.current) {
      return false
    } else {
      this.setData({
        currentTab: e[0].currentTarget.dataset.current
      })
    }
  }),
  /*滑动切换*/
  bindChange(e) {
    var _this = this;
    this.setData({
      currentTab: e.detail.current
    })
  },
  goDetail(e) {
    let id = JSON.stringify(e.currentTarget.dataset.item.id);
    wx.navigateTo({
      url: '../marketInfo-details/marketInfo-details?id=' + id,
      success: function(res) {},
      fail: function(res) {},
      complete: function(res) {},
    })

  },
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    this.loadData("领导关怀");
    this.loadData("制度规范");
    this.loadData("市场公告");
  },
  loadData(tabTitle = "领导关怀") {
    let param = {};
    param.n_type = tabTitle;
    param.page = 1;
    param.row = 10;
    wx.showLoading({
      title: '玩命加载中...',
    })
    wxRequest("/admin/notice/notice_info/getTitleList", param, "GET").then(res => {
      // var data = this.data.messageData;
      if (res.data.status == 1) {
        var arr = res.data.data.map(item => {
          return {
            imgUrl: item.img,
            title: item.title,
            date: item.date,
            id:item.id
          }
        })
        if (tabTitle == "领导关怀"){
          this.setData({
            messageData: arr
          })
        } else if (tabTitle == "制度规范"){
          this.setData({
            messageData2: arr
          })
        } else if (tabTitle == "市场公告"){
          this.setData({
            messageData3: arr
          })
        }
        wx.hideLoading()
      }

    })
  },
  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function() {

  }
}))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值