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 实现的全选和反选
Apr 15 Javascript
ExtJS 2.2.1的grid控件在ie6中的显示问题
May 04 Javascript
js中apply方法的使用详细解析
Nov 04 Javascript
node.js中的http.response.getHeader方法使用说明
Dec 14 Javascript
jquery复选框多选赋值给文本框的方法
Jan 27 Javascript
深入理解JavaScript系列(35):设计模式之迭代器模式详解
Mar 03 Javascript
如何在AngularJs中调用第三方插件库
May 21 Javascript
jq源码解析之绑在$,jQuery上面的方法(实例讲解)
Oct 13 jQuery
javascript+html5+css3自定义弹出窗口效果
Oct 26 Javascript
细说Vue组件的服务器端渲染的过程
May 30 Javascript
在Vue项目中,防止页面被缩放和放大示例
Oct 28 Javascript
JS中FileReader类实现文件上传及时预览功能
Mar 27 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
构建简单的Webmail系统
2006/10/09 PHP
用PHP和ACCESS写聊天室(八)
2006/10/09 PHP
PHP文章按日期(月日)SQL归档语句
2012/11/29 PHP
php页面防重复提交方法总结
2013/11/25 PHP
PHP使用PDO连接ACCESS数据库
2015/03/05 PHP
php的crc32函数使用时需要注意的问题(不然就是坑)
2015/04/21 PHP
PHP钩子与简单分发方式实例分析
2017/09/04 PHP
关于ThinkPHP中的异常处理详解
2018/05/11 PHP
日期处理的js库(迷你版)--自建js库总结
2011/11/21 Javascript
文字溢出实现溢出的部分再放入一个新生成的div中具体代码
2013/05/17 Javascript
jQuery实现新消息闪烁标题提示的方法
2015/03/11 Javascript
AngularJS中使用HTML5手机摄像头拍照
2016/02/22 Javascript
jQuery滚动插件scrollable.js用法分析
2017/05/25 jQuery
深入理解react-router 路由的实现原理
2018/09/26 Javascript
jquery实现聊天机器人
2020/02/08 jQuery
JavaScript监听键盘事件代码实现
2020/06/03 Javascript
详解vue-router的导航钩子(导航守卫)
2020/11/02 Javascript
Python标准库内置函数complex介绍
2014/11/25 Python
利用Python将文本中的中英文分离方法
2018/10/31 Python
Python发送邮件功能示例【使用QQ邮箱】
2018/12/04 Python
pytorch如何冻结某层参数的实现
2020/01/10 Python
python实现将range()函数生成的数字存储在一个列表中
2020/04/02 Python
在Tensorflow中实现leakyRelu操作详解(高效)
2020/06/30 Python
15个Pythonic的代码示例(值得收藏)
2020/10/29 Python
Python更改pip镜像源的方法示例
2020/12/01 Python
python爬虫线程池案例详解(梨视频短视频爬取)
2021/02/20 Python
python lambda的使用详解
2021/02/26 Python
HTML5里autofocus自动聚焦属性使用介绍
2016/06/22 HTML / CSS
六年级数学教学反思
2014/02/03 职场文书
分层教学实施方案
2014/03/19 职场文书
工人先进事迹材料
2014/12/26 职场文书
法定代表人资格证明书
2015/06/18 职场文书
运动会开幕式致辞
2015/07/29 职场文书
学者《孟子》名人名言
2019/08/09 职场文书
GitHub上77.9K的Axios项目有哪些值得借鉴的地方详析
2021/06/15 Javascript
Python 实现Mac 屏幕截图详解
2021/10/05 Python