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 相关文章推荐
静态页面下用javascript操作ACCESS数据库(读增改删)的代码
May 14 Javascript
jquery 入门教程 [翻译] 推荐
Aug 17 Javascript
getElementsByTagName vs selectNodes效率 及兼容的selectNodes实现
Feb 26 Javascript
jquery控制左右箭头滚动图片列表的实例
May 20 Javascript
window.navigate 与 window.location.href 的使用区别介绍
Sep 21 Javascript
用RadioButten或CheckBox实现div的显示与隐藏
Sep 21 Javascript
jquery解析xml字符串示例分享
Mar 25 Javascript
jQuery滚动条插件nanoscroller使用指南
Apr 21 Javascript
基于Jquery代码实现手风琴菜单
Nov 19 Javascript
详谈javascript异步编程
Feb 21 Javascript
jQuery自定义组件(导入组件)
Nov 08 Javascript
Angular4的输入属性与输出属性实例详解
Nov 29 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小技巧搜集,每个PHPer都来露一手
2007/01/02 PHP
php将数据库中所有内容生成静态html文档的代码
2010/04/12 PHP
php使用base64加密解密图片示例分享
2014/01/20 PHP
详解Grunt插件之LiveReload实现页面自动刷新(两种方案)
2015/07/31 PHP
PHP中CheckBox多选框上传失败的代码写法
2017/02/13 PHP
兼容ie和firefox js关闭代码
2008/12/11 Javascript
jQuery中click事件的定义和用法
2014/12/20 Javascript
JavaScript几种数组去掉重复值的方法推荐
2016/04/12 Javascript
深入浅析JavaScript中数据共享和数据传递
2016/04/25 Javascript
用原生JS对AJAX做简单封装的实例代码
2016/07/13 Javascript
Vue异步组件使用详解
2017/04/08 Javascript
JS数组去重常用方法实例小结【4种方法】
2018/05/28 Javascript
vue单页面实现当前页面刷新或跳转时提示保存
2018/11/02 Javascript
JS立即执行函数功能与用法分析
2019/01/15 Javascript
vue+web端仿微信网页版聊天室功能
2019/04/30 Javascript
使用微信SDK自定义分享的方法
2019/07/03 Javascript
vue简单练习 桌面时钟的实现代码实例
2019/09/19 Javascript
vue element-ui el-date-picker限制选择时间为当天之前的代码
2019/11/07 Javascript
JavaScript this使用方法图解
2020/02/04 Javascript
python实现ping的方法
2015/07/06 Python
python实现简单聊天应用 python群聊和点对点均实现
2017/09/14 Python
python命令行解析之parse_known_args()函数和parse_args()使用区别介绍
2018/01/24 Python
Python基于FTP模块实现ftp文件上传操作示例
2018/04/23 Python
pandas DataFrame索引行列的实现
2019/06/04 Python
python使用if语句实现一个猜拳游戏详解
2019/08/27 Python
利用pandas将非数值数据转换成数值的方式
2019/12/18 Python
tensorflow:指定gpu 限制使用量百分比,设置最小使用量的实现
2020/02/06 Python
python字符串下标与切片及使用方法
2020/02/13 Python
python多线程实现同时执行两个while循环的操作
2020/05/02 Python
Python学习之路安装pycharm的教程详解
2020/06/17 Python
Lululemon加拿大官网:加拿大知名体育服装零售商
2019/04/12 全球购物
为女性购买传统的印度服装和婚纱:Kalkifashion
2019/07/22 全球购物
大学生军训感想
2014/02/16 职场文书
房屋买卖委托书格式范本格式
2014/10/13 职场文书
关于童年的读书笔记
2015/06/26 职场文书
三严三实学习心得体会(精选N篇)
2016/01/05 职场文书