js原生实现FastClick事件

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

大家好,又见面了,我是你们的朋友全栈君。

js原生实现FastClick事件

注明:本人学习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事件能够访问到touchXtouchY。我采用了闭包的手法,这意味着每次new一个FastClickEvent事件对象,都要在内存中再次注入重复的handleEvent函数。至于重复的touchXtouchY,更是不必多说了。

新手求助:原本是想把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事件。

以上是一天的研究成果,如有转载,请注明【转载】

另求以上两个求助问题的解决思路或方案,求高手指点


参考资料:

《JavaScript高级程序设计第三版》

【读fastclick源码有感】彻底解决tap“点透”,提升移动端点击响应速度

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150821.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • sql 存储过程中何时使用declare声明变量[通俗易懂]

    sql 存储过程中何时使用declare声明变量[通俗易懂]这个问题我从百度第二页才找得到答案,就从别人的答案自己仔细研究懂了,顺便整理了过来。原文链接:https://zhidao.baidu.com/question/245490659799230284.html如果把存储过程看作是批处理语句就好理解多了存储过程只不过是一个带着名称的SQL批处理语句,如果在整个过程中需要变量时就是可以声明,但该变量声明后只能存活在批处理(存储过程)的…

    2022年8月20日
    5
  • linux防火墙查看状态firewall、iptable[通俗易懂]

    linux防火墙查看状态firewall、iptable[通俗易懂]CentOS7的防火墙配置跟以前版本有很大区别,CentOS7这个版本的防火墙默认使用的是firewall,与之前的版本Centos6.x使用iptables不一样一、iptables防火墙1、基本操作#查看防火墙状态serviceiptablesstatus#停止防火墙serviceiptablesstop#启动防火墙serviceipt…

    2022年4月19日
    111
  • OpenResty 最佳实践学习–实战演习笔记(4)

    本篇简单记录openresty连接redis数据库和缓存的一些东西,也基本上是官网上的一些例子和知识,作为整理方便自己后续回顾!openresty连接redis因为我本地服务器安装了redis,这里只简单记录连接redis的过程!1.启动redis服务[root@localhost ~]# /usr/local/bin/redis-server /root/dufy/redis/redis-3.0.

    2022年2月26日
    71
  • JavaScript 对象Array,Map,Set使用

    for(int i = 0 ;i 在说明每个对象的用法之前,首先说明 JavaScript 对象的使用一定要注意浏览器的兼容性问题!尤其是IE的版本!!!! }想查看具体的API请查询 JavaScript 对象 这里面有具体的API介绍!Array,Map,Set使用细则参考上面的JavaScript 对象!下面主要说一下Map!MapJavaScript 的Map

    2022年2月26日
    49
  • hdu 4912 Paths on the tree(lca+馋)

    hdu 4912 Paths on the tree(lca+馋)

    2022年1月11日
    29
  • RST报文详解_modbus网关使用方法

    RST报文详解_modbus网关使用方法我们知道TCP建立连接的时候需要三次连接,TCP释放连接的时候需要四次挥手,在这个过程中,出现了很多特殊的标志报文段,例如SYNACKFIN,在TCP协议中,除了上面说了那些标志报文段之外,还有其他的报文段,如PUSH标志报文段以及今天需要重点讲解的RST报文段。RST:(Resettheconnection)用于复位因某种原因引起出现的错误连接,也用来拒绝非法数据和请求。如果接收到R…

    2022年10月1日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号