[Sencha Touch/ExtJS] (函数节流)阻止用户快速频繁点击,导致多次触发点击事件

原文链接:http://blog.csdn.net/lovelyelfpop/article/details/72730455

一、前言

以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃。

  • window对象的resizescroll事件

  • 拖拽时的mousemove事件

  • 射击游戏中的mousedownkeydown事件

  • 文字输入、自动完成的keyup事件

实际上对于window的resize事件,实际需求大多为停止改变大小n毫秒后执行后续处理;而其他事件大多的需求是以一定的频率执行后续处理。针对这两种需求就出现了debounce和throttle两种解决办法。

函数去抖(debounce)

如果用手指一直按住一个弹簧,它将不会弹起直到你松手为止。

也就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。

函数节流(throttle)

如果将水龙头拧紧直到水是以水滴的形式流出,那你会发现每隔一段时间,就会有一滴水流出。

也就是会说预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。

二、Sencha Touch/ExtJS 中防止频繁触发点击事件

比如我们想要这样的效果:

用户在500ms内,如果多次点击按钮或列表项,那么点击事件只触发一次(即第一次点击时触发)。

我们可以拦截点击事件的触发(fireEvent),这就需要用到sencha中的beforeafter来实现”拦截器”了。

下面代码有两个实现,一种用Mixin实现,另一种用Plugin实现。其中前者用在类中(即define的时候),后者用在类的实例(Ext.Create/Ext.widget/Ext.factory等)中。

支持Ext.ButtonExt.DataViewExt.List

支持自定义节流的时间间隔,单位ms,默认500ms

Mixin:

//ExtJS 6
Ext.define("UX.mixin.Throttle", {
    extend: "Ext.Mixin", //如果是Sencha Touch, 这里换成"Ext.mixin.Mixin"

    mixinConfig: {
        id: 'throttle',
        before: {
            onTap: 'onBeforeTapThrottle',
            onItemTap: 'onBeforeItemTapThrottle'
        },
        after: {
            onTap: 'onAfterTapThrottle',
            onItemTap: 'onAfterItemTapThrottle'
        }
    },

    throttleDuration: 500,

    onBeforeTapThrottle: function() {
        //console.log('before tap');
        if (this._justTapped && new Date().getTime() - this._justTapped <= this.throttleDuration) {
            //console.log('throttle');
            return false;
        }
        return true;
    },
    onAfterTapThrottle: function() {
        //console.log('after tap');
        this._justTapped = new Date().getTime();
    },

    onBeforeItemTapThrottle: function() {
        //console.log('before itemtap');
        if (this._itemJustTapped && new Date().getTime() - this._itemJustTapped <= this.throttleDuration) {
            //console.log('throttle');
            return false;
        }
        return true;
    },
    onAfterItemTapThrottle: function() {
        //console.log('after itemtap');
        this._itemJustTapped = new Date().getTime();
    }
});

//Sencha Touch
Ext.define("UX.mixin.Throttle", {
    extend: "Ext.mixin.Mixin", 

    mixinConfig: {
        id: 'throttle',
        beforeHooks: {
            onBeforeTapThrottle: 'onTap',
            onBeforeItemTapThrottle: 'onItemTap'
        },
        afterHooks: {
            onAfterTapThrottle: 'onTap',
            onAfterItemTapThrottle: 'onItemTap'
        }
    },

    throttleDuration: 500,

    onBeforeTapThrottle: function() {
        //console.log('before tap');
        if (this._justTapped && new Date().getTime() - this._justTapped <= this.throttleDuration) {
            //console.log('throttle');
            return false;
        }
        return true;
    },
    onAfterTapThrottle: function() {
        //console.log('after tap');
        this._justTapped = new Date().getTime();
    },

    onBeforeItemTapThrottle: function() {
        //console.log('before itemtap');
        if (this._itemJustTapped && new Date().getTime() - this._itemJustTapped <= this.throttleDuration) {
            console.log('throttle');
            return false;
        }
        return true;
    },
    onAfterItemTapThrottle: function() {
        //console.log('after itemtap');
        this._itemJustTapped = new Date().getTime();
    }
});

用法如下:

//requires: 'UX.mixin.Throttle'

//自定义list类
Ext.define('MyApp.view.MyList', {
    extend: 'Ext.List',

    mixins: ['UX.mixin.Throttle'],

    throttleDuration: 1000 //节流的时间间隔, 单位ms, 默认500ms
});

//自定义button类
Ext.define('MyApp.view.MyButton', {
    extend: 'Ext.Button',

    mixins: ['UX.mixin.Throttle'],

    throttleDuration: 1000 //节流的时间间隔, 单位ms, 默认500ms
});

Plugin:

Ext.define('UX.plugin.Throttle', {
    extend: 'UX.mixin.Throttle',
    alias: 'plugin.throttle',
    pluginId: 'throttle',
    isPlugin: true,

    init: function(cmp) {
        if (cmp instanceof Ext.DataView) {
            cmp.onBefore({
                itemtap: 'onBeforeItemTapThrottle',
                scope: this
            });
            cmp.onAfter({
                itemtap: 'onAfterItemTapThrottle',
                scope: this
            });
        } else {
            cmp.onBefore({
                tap: 'onBeforeTapThrottle',
                scope: this
            });
            cmp.onAfter({
                tap: 'onAfterTapThrottle',
                scope: this
            });
        }
    }
});

用法如下:

//requires: 'UX.plugin.Throttle'
{
    xtype: 'button',
    text: '扫一扫',
    handler: function() {
        //点击事件的逻辑
    },
    plugins: ['throttle']
}, {
    xtype: 'button',
    text: '完成',
    handler: function() {
        //点击事件的逻辑
    },
    plugins: [{
        type: 'throttle',
        throttleDuration: 1000 //节流的时间间隔, 单位ms, 默认500ms
    }]
}, {
    xtype: 'list',
    plugins: ['throttle']
}

测试结果

连续快速2次点击,控制台输出如下:

dataview/list 测试结果

before itemtap
itemtap
after itemtap

before itemtap
throttle
after itemtap

button 测试结果

before tap
tap
after tap

before tap
throttle
after tap
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

神秘_博士

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值