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+ajax请求data显示在GridView上(asp.net)
Aug 27 Javascript
再谈querySelector和querySelectorAll的区别与联系
Apr 20 Javascript
Google (Local) Search API的简单使用介绍
Nov 28 Javascript
node.js中的events.emitter.removeListener方法使用说明
Dec 10 Javascript
jquery实现的Accordion折叠面板效果代码
Sep 02 Javascript
超漂亮的jQuery图片轮播特效
Nov 24 Javascript
Bootstrap每天必学之日期控制
Mar 07 Javascript
关于laydate.js加载laydate.css路径错误问题解决
Dec 27 Javascript
一份超级详细的Vue-cli3.0使用教程【推荐】
Nov 15 Javascript
详解Vue.directive 自定义指令
Mar 27 Javascript
详解vue中router-link标签所必备了解的属性
Apr 15 Javascript
Vue常用API、高级API的相关总结
Feb 02 Vue.js
常用原生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中使用sockets:从新闻组中获取文章
2006/10/09 PHP
gd库图片下载类实现下载网页所有图片的php代码
2012/08/20 PHP
兼容各大浏览器带关闭按钮的漂浮多组图片广告代码
2014/06/05 PHP
ThinkPHP实现事务回滚示例代码
2014/06/23 PHP
PHP速成大法
2015/01/30 PHP
PHP中ajax无刷新上传图片与图片下载功能
2017/02/21 PHP
Laravel框架分页实现方法分析
2018/06/12 PHP
飞鱼(shqlsl) javascript作品集
2006/12/16 Javascript
JavaScript去掉空格的方法集合
2010/12/28 Javascript
jQuery的attr与prop使用介绍
2013/10/10 Javascript
jQuery 无刷新分页实例代码
2013/11/12 Javascript
快速解决jQuery与其他库冲突的方法介绍
2014/01/02 Javascript
基于jQuery通过jQuery.form.js插件实现异步上传
2015/12/13 Javascript
使用NodeJs 开发微信公众号(三)微信事件交互实例
2016/03/02 NodeJs
基于Angularjs实现分页功能
2016/05/30 Javascript
canvas实现爱心和彩虹雨效果
2017/03/09 Javascript
利用React Router4实现的服务端直出渲染(SSR)
2019/01/07 Javascript
Node.js设置定时任务之node-schedule模块的使用详解
2020/04/28 Javascript
python修改字典内key对应值的方法
2015/07/11 Python
python通过pip更新所有已安装的包实现方法
2017/05/19 Python
python实现决策树分类(2)
2018/08/30 Python
如何用OpenCV -python3实现视频物体追踪
2019/12/04 Python
Python基于Webhook实现github自动化部署
2020/11/28 Python
如何利用Python matplotlib绘制雷达图
2020/12/21 Python
css3和jquery实现的可折叠导航菜单适合放在手机网页的导航菜单
2014/09/02 HTML / CSS
css3利用transform变形结合事件完成扇形导航
2020/10/26 HTML / CSS
Tech21美国/加拿大:英国NO.1防摔保护壳品牌
2018/01/20 全球购物
德国二手设计师时装和复古时装跳蚤市场:Mädchenflohmarkt
2020/11/09 全球购物
网站编辑求职信
2013/10/17 职场文书
项目专员岗位职责
2013/12/04 职场文书
采购求职信
2014/03/17 职场文书
2014年重阳节活动策划方案书
2014/09/16 职场文书
2015年车间主任工作总结
2015/05/21 职场文书
django中websocket的具体使用
2022/01/22 Python
JavaScript中reduce()的用法
2022/05/11 Javascript
Java代码规范与质量检测插件SonarLint的使用
2022/08/05 Java/Android