跳至主要內容

微信小程序按钮防抖节流设计新思路

Mr.Cao...大约 3 分钟微信小程序miniprogram

前言

在现在的业务开发中有很多需要用户主动操作的按钮,比方说提交订单,加入购物车等

这些场景在网路波动时候,服务端响应慢的话可能造成用户感知不强,用户不知道是否成功就会

导致用户短时间内多次点击,那么在前端有一些解决方案的那就是防抖和节流。

解决方案

方案一

防抖和节流的区别

防抖和节流的区别在于触发事件的时间,防抖是当事件触发n秒后才执行回调,节流是当事件触发n秒内只执行一次回调。

防抖和节流的应用场景也不一样,防抖适用于用户输入,节流适用于用户操作频繁的场景。

节流

节流就是在一段时间内,只能触发一次事件,如果在这段时间内又触发了事件,则在这段时间内忽略

这次事件,直到这段时间结束后,才能再次触发事件。

function throttle(fn, delay) {
    let timer = null;
    return function () {
        let context = this;
        let args = arguments;
        if (!timer) {
            timer = setTimeout(function () {
                fn.apply(context, args);
                timer = null;
            }, delay);
        }
    }
}

防抖

防抖就是在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

function debounce(fn, delay) {
    let timer = null;
    return function () {
        let context = this;
        let args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            fn.apply(context, args);
        }, delay);
    }
}

防抖和节流的应用场景

防抖和节流的应用场景也不一样,防抖适用于用户输入,节流适用于用户操作频繁的场景。但是这些都是js层面中断了操作,并不是真正的阻塞用户的操作,所以在实际开发中,我们需要结合业务场景来选择使用。

方案二

该方案是利用小程序的wxs方法实现的。

具体原理就是在wxs中触发点击的时候,给当前节点下边添加一个node,这个node这个节点的大小
跟按钮一模一样,层级设置为-1,当点击时候开始执行动画,此时 层级变成1,覆盖在点击元素上方
此时重复点击,实际上点击的并不是目标元素,
在指定时间内动画,当动画执行完毕拿到回调,再次改node 层级为-1,代码如下:

<!--basic-components/debounceElement/index.wxml-->
<wxs module="tool" src="./index.wxs"></wxs>
<view class="debounce-content" capture-bind:tap="{{tool.tap}}">
    <view class="debounce-mark"
          style="--debounce-time: {{time}}s"
          bind:animationend="{{tool.end}}"
    >
    </view>
    <slot/>
</view>
// basic-components/debounceElement/index.js
Component({
    /**
     * 组件的属性列表
     */
    properties: {
        time: { // isPromise为false时生效
            type: Number,
            value: 1
        },
    },

})

wxs代码如下

// basic-components/debounceElement/index.wxs
function tap(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.debounce-mark');
    instance && instance.addClass && instance.addClass('loading');
}

function end(event, ownerInstance) {
    var instance = ownerInstance.selectComponent('.debounce-mark');
    instance && instance.removeClass && instance.removeClass('loading');
}

module.exports = {
    tap: tap,
    end: end
}

重点是下边样式代码

/* basic-components/debounceElement/index.wxss */
.debounce-content {
    width: fit-content;
    height: fit-content;
    position: relative;
}

.debounce-mark {
    position: absolute;
    width: 100%;
    height: 100%;
    top: 0;
    left: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: row;
    background: transparent;
    z-index: -1;
}

.loading::before {
    content: attr(data-text);
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: #999;
}

.loading {
    /*动画执行时间 极为节流间隔时间*/
    animation: run var(--debounce-time) step-end;
    animation-fill-mode: forwards;
}

@keyframes run {
    from {
        z-index: 1;
    }
    to {
        z-index: -1;
    }
}

使用方法

<debounce-element>
    <button block="{{true}}" bindtap="onSendRequest">发送请求</button>
</debounce-element>
<!--此时这个onSendRequest方法会在1s内只触发一次-->

以上可以使用一个动画演示:

请注意,红色方块 即为重点

对比

方案一

  • 是在js执行,需要监听回调函数,比较通用

方案二

  • 利用小程序的wxs方法实现,可以直接在wxml中触发事件,不需要监听回调函数
上次编辑于:
贡献者: CaoFangshuai,Caofangshuai
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8