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的下拉框改变动态添加和删除表格实现代码
Sep 12 Javascript
JavaScript闭包 懂不懂由你反正我是懂了
Oct 21 Javascript
jquery实现tr元素的上下移动示例代码
Dec 20 Javascript
javascript中定义类的方法详解
Feb 10 Javascript
js通过classname来获取元素的方法
Nov 24 Javascript
js canvas实现放大镜查看图片功能
Jun 08 Javascript
JavaScript实现删除数组重复元素的5种常用高效算法总结
Jan 18 Javascript
vue 巧用过渡效果(小结)
Sep 22 Javascript
vue实现文字横向无缝走马灯组件效果的实例代码
Apr 09 Javascript
JavaScript canvas实现雪花随机动态飘落
Feb 08 Javascript
深入解读VUE中的异步渲染的实现
Jun 19 Javascript
vue+Element-ui实现登录注册表单
Nov 17 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
给apache2.2加上mod_encoding模块後 php5.2.0 处理url出现bug
2007/04/12 PHP
PHP+Mysql+jQuery实现发布微博程序 jQuery篇
2011/10/08 PHP
php版微信公众平台回复中文出现乱码问题的解决方法
2016/09/22 PHP
ThinkPHP 模板引擎使用详解
2017/05/07 PHP
详解PHP5.6.30与Apache2.4.x配置
2017/06/02 PHP
php中get_object_vars()在数组的实例用法
2021/02/22 PHP
javascript编程起步(第五课)
2007/01/10 Javascript
用js判断用户浏览器是否是XP SP2的IE6
2007/03/08 Javascript
JQuery的ajax获取数据后的处理总结(html,xml,json)
2010/07/14 Javascript
DOM 中的事件处理介绍
2012/01/18 Javascript
学习JavaScript设计模式之迭代器模式
2016/01/19 Javascript
用NODE.JS中的流编写工具是要注意的事项
2016/03/01 Javascript
jquery封装插件时匿名函数形参和实参的写法解释
2017/02/14 Javascript
jsonp跨域请求详解
2017/07/13 Javascript
Vue-router 类似Vuex实现组件化开发的示例
2017/09/15 Javascript
vue中使用vue-router切换页面时滚动条自动滚动到顶部的方法
2017/11/28 Javascript
vue中使用cropperjs的方法
2018/03/01 Javascript
使用webpack打包后的vue项目如何正确运行(express)
2018/10/26 Javascript
微信小程序带动画弹窗组件使用方法详解
2018/11/27 Javascript
vue中使用vue-cli接入融云实现即时通信
2019/04/19 Javascript
修改layui的后台模板的左侧导航栏可以伸缩的方法
2019/09/10 Javascript
使用vue-cli4.0快速搭建一个项目的方法步骤
2019/12/04 Javascript
vue中的使用token的方法示例
2020/03/10 Javascript
[00:35]可解锁地面特效
2018/12/20 DOTA
python中的decimal类型转换实例详解
2019/06/26 Python
selenium框架中driver.close()和driver.quit()关闭浏览器
2020/12/08 Python
python里glob模块知识点总结
2021/01/05 Python
黄色火烈鸟:De Gele Flamingo
2019/03/18 全球购物
法国在线药房:DoctiPharma
2020/10/21 全球购物
Unix控制后台进程都有哪些进程
2016/09/22 面试题
交通事故协议书范文
2014/04/16 职场文书
学习党的群众路线实践活动思想汇报
2014/09/12 职场文书
护士工作失误检讨书
2014/09/14 职场文书
体育运动会广播稿
2014/10/05 职场文书
2014年小学校长工作总结
2014/12/08 职场文书
Python读取文件夹下的所有文件实例代码
2021/04/02 Python