[Sencha Touch/ExtJS] (函数节流)阻止用户快速频繁点击,导致多次触发点击事件
2017-05-25 16:05
633 查看
原文链接:http://blog.csdn.net/lovelyelfpop/article/details/72730455
window对象的
拖拽时的
射击游戏中的
文字输入、自动完成的
实际上对于window的
也就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。
也就是会说预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
用户在
我们可以拦截点击事件的触发(
下面代码有两个实现,一种用
支持
支持自定义节流的时间间隔,单位
用法如下:
用法如下:
一、前言
以下场景往往由于事件频繁被触发,因而频繁执行DOM操作、资源加载等重行为,导致UI停顿甚至浏览器崩溃。window对象的
resize、
scroll事件
拖拽时的
mousemove事件
射击游戏中的
mousedown、
keydown事件
文字输入、自动完成的
keyup事件
实际上对于window的
resize事件,实际需求大多为停止改变大小n毫秒后执行后续处理;而其他事件大多的需求是以一定的频率执行后续处理。针对这两种需求就出现了debounce和throttle两种解决办法。
函数去抖(debounce)
如果用手指一直按住一个弹簧,它将不会弹起直到你松手为止。也就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用此动作则将重新计算执行时间。
函数节流(throttle)
如果将水龙头拧紧直到水是以水滴的形式流出,那你会发现每隔一段时间,就会有一滴水流出。也就是会说预先设定一个执行周期,当调用动作的时刻大于等于执行周期则执行该动作,然后进入下一个新周期。
二、Sencha Touch/ExtJS 中防止频繁触发点击事件
比如我们想要这样的效果:用户在
500ms内,如果多次点击按钮或列表项,那么点击事件只触发一次(即第一次点击时触发)。
我们可以拦截点击事件的触发(
fireEvent),这就需要用到sencha中的
before和
after来实现”拦截器”了。
下面代码有两个实现,一种用
Mixin实现,另一种用
Plugin实现。其中前者用在类中(即
define的时候),后者用在类的实例(
Ext.Create/
Ext.widget/
Ext.factory等)中。
支持
Ext.Button和
Ext.DataView、
Ext.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
相关文章推荐
- [Sencha ExtJS Modern & Touch] 让长按(taphold/itemtaphold)操作完成后不触发点击(tap/itemtap)事件
- 避免点击触发多个按钮和快速点击多次触发事件
- Code Fragment-避免用户多次快速的点击事件
- Spread for Windows Forms快速入门(8)---单元格中用户动作触发的事件
- 快速移动鼠标导致js 的mouseover,mouseout,mouseenter,mouseleave等事件(触发动画)反复叠加的处理
- [Phonegap+Sencha Touch] 移动开发16 安卓webview中,input输入框不触发backspace回退键事件的解决办法(带来其他bug,作废)
- JavaScript 频繁发射事件处理的优化 --- 函数节流/事件稀释
- Sencha Touch 给 Panel 注册点击事件(tap)和其他touchstart,touchend 等事件
- js触发单击事件(不是调用某组件定义的单击函数,而是触发,相当于你点击)
- jquery mobile的触控点击事件会多次触发问题的解决方法
- [Phonegap+Sencha Touch] 移动开发21 Sencha touch tapHold事件 触发时间太长的解决办法
- [Phonegap+Sencha Touch] 移动开发26 Android下的sencha touch程序,转屏时,Ext.Viewport不能触发orientationchange事件的解决办法
- JavaScript 频繁发射事件处理的优化 --- 函数节流/事件稀释
- 防止用户多次点击按钮导致页面被多次提交
- [Phonegap+Sencha Touch] 移动开发26 Android下的sencha touch程序,转屏时,Ext.Viewport不能触发orientationchange事件的解决办法
- CheckBox在ListView中导致其点击事件不会被触发解决方法
- Sencha-touch之TabPanel的Tab在点击时实施事件
- 第15天 Android Touch事件学习 2 触发点击事件的地方
- 防止用户多次点击按钮,导致发送多次请求或者其他问题。
- 一个阻止用户多次点击的弹窗