js原生实现FastClick事件的实例


Posted in Javascript onNovember 20, 2016

注明:本人学习javascript时间不长,最近一直在做web端的手机网页和微信应用,由于最近有用到类似fastclick的功能,在原来的程序中用touchstart和touchend事件模拟,现在尝试将其封装,得到了以下两种有问题的方案。分享给大家,另求大神指导

在手机端Web app开发中,click事件的300ms的延迟,会造成响应缓慢,尤其在低端机中尤为明显。而使用touchstart或者touchend事件,会和默认的滚轮事件发生冲突,这也不是我们所期望的。

所以,自己动手,丰衣足食,写了一个快速点击事件的原生js代码(考虑到web app开发的环境,我们暂时无需考虑对IE等浏览器的兼容)。

实现方法1如下:

function FastClickEvent(handler){
  var fastclick = {
    handler : handler,
    bind : function(query){
      var targetList = document.querySelectorAll(query);
      for(var i=0,len=targetList.length;i<len;i++)
      {
        targetList[i].addEventListener('touchstart',handleEvent);
        targetList[i].addEventListener('touchend',handleEvent);
      }
    },
    unbind : function(query){
      var targetList = document.querySelectorAll(query);
      for(var i=0,len=targetList.length;i<len;i++)
      {
        targetList[i].removeEventListener('touchstart',handleEvent);
        targetList[i].removeEventListener('touchend',handleEvent);
      }
    }  
  }
  var touchX = 0 ,touchY = 0;

  function handleEvent(event){
    switch(event.type)
    {
      case 'touchstart':
        touchX = event.touches[0].clientX;
        touchY = event.touches[0].clientY;
        break;
      case 'touchend':
        var x = event.changedTouches[0].clientX;
        var y = event.changedTouches[0].clientY;
        if(Math.abs(touchX-x)<5||Math.abs(touchY-y)<5)
          fastclick.handler(event);
        break;
    }
  };

  return fastclick;
};

原理:根据连续touchstart和touchend事件发生时位置的变化,来判断是否是一次点击

调用:用一个handler函数来注册一个FastClickEvent事件。然后将注册好的FastClickEvent事件,通过bind方法,绑定到对应的元素上去。如下:

var handler = function(event){
  console.log(event.target.id+" fastclicked");
}
var fastClick = new FastClickEvent(handler);
fastClick.bind("div");

这段代码,我们给所有的div元素注册了fastclick的handler事件。调用fastClick.unbind来解除元素的绑定。

但是这段代码有一个问题,为了让handleEvent事件能够访问到touchX,touchY。我采用了闭包的手法,这意味着每次new一个FastClickEvent事件对象,都要在内存中再次注入重复的handleEvent函数。至于重复的touchX,touchY,更是不必多说了。

新手求助:原本是想把handleEvent函数写到原型里,但是产生的一个问题是handleEvent(event)的this对象是windows,也就是说,我取不到touchX和touchY以及handler对象,造成访问错误。

有一种比较简单的解决思路,就是只注册一个fastClickEvent事件,然后在处理程序中根据event.target的实际值(即发生事件的对象上)来决定响应的内容。

但是,这意味着你必须对所有的fastclick事件都非常熟悉。

用这种方法带来的好处在于,由于你只有一个handleEvent函数,所以基本来说,在页面释放之前,除非是你不想再触发fastclick事件,否则无需去解绑任何元素的fastclick事件(即使你解绑了,内存中仍然存在该handler函数)。而且,你可以很方便的用bind(query)来添加任何动态生成的元素的fastclick事件,只要你在handler函数中已经写好相应的处理程序。

如果你想添加多个fastclick事件,而且可能要在多个地方注册,那么也只要new一个新的FastClickEvent对象,然后绑定到对应的元素中去就可以了。

下面,介绍一种使用EventTarget类的方法。首先看一下EventTarget

function EventTarget(){
  this.handlers = {};
}
EventTarget.prototype = {
  constructor: EventTarget,
  addHandler : function(type,handler){
    if(typeof this.handlers[type] == "undefined"){
      this.handlers[type]=[];
    }
    this.handlers[type].push(handler);
  },
  fire : function(event){
    if(!event.target){
      event.target = this;
    }
    if(this.handlers[event.type] instanceof Array){
      var handlers = this.handlers[event.type];
      for(var i=0,len=handlers.length;i<len;i++){
        handlers[i](event);
      }
    }
  },
  removeHandler : function(type,handler){
    if(this.handlers[type] instanceof Array){
      var handlers = this.handlers[type];
      for(var i=0,len=handler.length;i<len;i++){
        if(handlers[i]==handler){
          break;
        }
      }
      handlers.splice(i,1);
    }
  }
}

这个类,是一个用来添加、移除以及实现自定义类的接口。参考《JavaScript高级程序设计第三版》P616-617

那么,如何把这个类,变成我们的fastclick事件接口呢?

定义一个全局变量,用这个变量来完成所有的fastclick事件注册、删除以及添加

var FastClick = function(){

  var fastclick = new EventTarget(), 
    touchX = 0 ,
    touchY = 0;

  function handleEvent(event){
    switch(event.type)
    {
      case 'touchstart':
        touchX = event.touches[0].clientX;
        touchY = event.touches[0].clientY;
        break;
      case 'touchend':
        var x = event.changedTouches[0].clientX;
        var y = event.changedTouches[0].clientY;
        if(Math.abs(touchX-x)<5||Math.abs(touchY-y)<5)
          fastclick.fire({type:'fastclick',target:event.target});
        break;
    }
  };
  fastclick.bind = function(query)
  {
    var targetList = document.querySelectorAll(query);
    for(var i=0,len=targetList.length;i<len;i++)
    {
      targetList[i].addEventListener('touchstart',handleEvent);
      targetList[i].addEventListener('touchend',handleEvent);
    }
  }

  Fastclick.unbind = function(query){
    var targetList = document.querySelectorAll(query);
    for(var i=0,len=targetList.length;i<len;i++)
    {
      targetList[i].removeEventListener('touchstart',handleEvent);
      targetList[i].removeEventListener('touchend',handleEvent);
    }
  }
  return fastclick;
}();

这个全局变量FastClick可以用来添加任意的fastclick事件。

下面来讲讲如何调用。

添加事件函数:

FastClick.addHandler('fastclick',function(event){});

删除事件函数://匿名事件无法删除

FastClick.removeHandler('fastclick',handler);

绑定元素

FastClick.bind("div");

解绑

FastClick.unbind("div");

这个方法,同样需要我们在handler事件中对event.target做预判,因为虽然这种方法可以添加多个fastclick事件,但是,事件在执行的过程中是按顺序一个一个执行的,也就是说,可能会执行你并不想执行的函数。

带来的好处在于,可以注册多个fastclick事件,而且无需再次绑定,就可以执行了。
比如说,

FastClick.bind("div");
FastClick.addHandler(handler1);
FastClick.addHandler(handler2);

那么,当快速点击事件发生在任一div元素时,就会顺序执行handler1和handler2。

如果我们调用removeHandler来删除handler1或handler2,那么相应的函数就不会再执行了。

另外,需要注意的是,在handler函数中,this对象是FastClick.handlers['fastclick']这个数组,一般情况下,我们用event.target来获取发生事件的对象。

用这种方法,基本克服了上面方法的问题,而且,对这个对象重复new并没有多大的意义,除非你不想对event.target做预判,从而生成一大堆的FaskClick类,但这显然是不高效的。

新手求助:如何能够实现特定的元素的绑定执行的函数,也就是: 能够调用FastClick.bind(query,handler);实现对符合query条件的元素添加handler的fastclick事件。

以上就是小编为大家带来的js原生实现FastClick事件的实例全部内容了,希望大家多多支持三水点靠木~

Javascript 相关文章推荐
用jquery和json从后台获得数据集的代码
Nov 07 Javascript
jQuery prev ~ siblings选择器使用介绍
Aug 09 Javascript
jQuery.event兼容各浏览器的event详细解析
Dec 18 Javascript
JavaScript实现存储HTML字符串示例
Apr 21 Javascript
javascript实现切换td中的值
Dec 05 Javascript
Javascript中的apply()方法浅析
Mar 15 Javascript
在React框架中实现一些AngularJS中ng指令的例子
Mar 06 Javascript
jQuery siblings()用法实例详解
Apr 26 Javascript
jQuery 局部div刷新和全局刷新方法总结
Oct 05 Javascript
xcode中获取js文件的路径方法(推荐)
Nov 05 Javascript
基于jquery二维码生成插件qrcode
Jan 07 Javascript
基于Taro的微信小程序模板消息-获取formId功能模块封装实践
Jul 15 Javascript
常用原生js自定义函数总结
Nov 20 #Javascript
浅谈js之字面量、对象字面量的访问、关键字in的用法
Nov 20 #Javascript
浅谈jquery选择器 :first与:first-child的区别
Nov 20 #Javascript
关于js函数解释(包括内嵌,对象等)
Nov 20 #Javascript
浅谈js函数中的实例对象、类对象、局部变量(局部函数)
Nov 20 #Javascript
解决前端跨域问题方案汇总
Nov 20 #Javascript
jQuery 的 ready()的纯js替代方法
Nov 20 #Javascript
You might like
PHP扩展开发入门教程
2015/02/26 PHP
LINUX下PHP程序实现WORD文件转化为PDF文件的方法
2016/05/13 PHP
thinkPHP简单导入和使用阿里云OSSsdk的方法
2017/03/15 PHP
浅析PHP7 的垃圾回收机制
2019/09/06 PHP
跨浏览器的设置innerHTML方法
2006/09/18 Javascript
IE bug table元素的innerHTML
2010/01/11 Javascript
转换json格式的日期为Javascript对象的函数
2010/07/13 Javascript
js各种验证文本框输入格式(正则表达式)
2010/10/22 Javascript
JavaScript 处理Iframe自适应高度(同或不同域名下)
2013/03/29 Javascript
使用javascript过滤html的字符串(注释标记法)
2013/07/08 Javascript
jQuery关于导航条背景切换效果实现示例
2013/09/04 Javascript
jQuery选择器源码解读(八):addCombinator函数
2015/03/31 Javascript
JS实现复制内容到剪贴板功能兼容所有浏览器(推荐)
2016/06/17 Javascript
checkbox批量选中,获取选中项的值的简单实例
2016/06/28 Javascript
原生JS实现轮播效果+学前端的感受(防止走火入魔)
2016/08/21 Javascript
基于jQuery代码实现圆形菜单展开收缩效果
2017/02/13 Javascript
JS库之Highlight.js的用法详解
2017/09/13 Javascript
element-ui表格列金额显示两位小数的方法
2018/08/24 Javascript
关于uniApp editor微信滑动问题
2021/01/15 Javascript
[03:36]DOTA2完美大师赛coL战队趣味视频——我演你猜
2017/11/23 DOTA
Python实现图片转字符画的示例代码
2017/08/21 Python
Python3中条件控制、循环与函数的简易教程
2017/11/21 Python
Python中请不要再用re.compile了
2019/06/30 Python
基于MATLAB和Python实现MFCC特征参数提取
2019/08/13 Python
Python pandas实现excel工作表合并功能详解
2019/08/29 Python
Python3读写Excel文件(使用xlrd,xlsxwriter,openpyxl3种方式读写实例与优劣)
2020/02/13 Python
基于python爬取有道翻译过程图解
2020/03/31 Python
为什么在使用动态 SQL 语句时必须为低层数据库对象授予权限
2012/12/13 面试题
.NET面试10题
2014/02/24 面试题
nohup的用法
2012/11/26 面试题
2014政府领导班子对照检查材料思想汇报(3篇)
2014/09/26 职场文书
党员自我剖析材料范文
2014/10/06 职场文书
Nginx内网单机反向代理的实现
2021/11/07 Servers
MySQL 外连接语法之 OUTER JOIN
2022/04/09 MySQL
Tomcat执行startup.bat出现闪退的原因及解决办法
2022/04/20 Servers
vue里使用create, mounted调用方法
2022/04/26 Vue.js