移动端fastClick的原理解析

移动设备上的浏览器默认会在用户点击屏幕大约延迟300毫秒后才会触发点击事件,这是为了检查用户是否在做双击。为了能够立即响应用户的点击事件,我们需要对移动端的点击事件做下处理。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .box1 {
            width: 200px;
            height: 100px;
            background: red;;
        }
    </style>
</head>
<body>
    <div class="box1" id='box11'></div>
</body>
<script src="h5.js"></script>
<script>
    window.onload = function() {
        var eleBox = document.getElementById('box11');
        eleBox.addEventListener('click', function() {
            console.log('click')
        })
        eleBox.addEventListener('touchstart', function() {
            console.log('touchstart')
        })
       
    }
    
</script>
</html>

打开浏览器,调成手机模式,点击div,会发现touchstart先触发,click会在300ms后触发,这就是手机端点击时间的延迟。

我们给div增加一个startend事件,看看会怎样?

 eleBox.addEventListener('touchend', function() {
    console.log('touchend')
 })

点击发现,touchstart和touchend都在click之前触发,这就是说,如果我们禁止掉click事件,用touchstart和touchend两个事件的时间差去处理click事件,是不是就能解决300ms的延迟问题了呢?我们来试一下。

fastClick.js

(function(window) {
    'use stirct'
    function myMobile(selector) {
        return myMobile.prototype._init(selector)
    }
    myMobile.prototype = {
        _init: function(selector) {
            if (typeof selector === 'string') {
                this.ele = window.document.querySelector(selector);
                return this;
            }
        },
        // 单机事件
        tab: function(handler) {
            this.ele.addEventListener("touchstart", touchFn);
            this.ele.addEventListener("touchend", touchFn);
            var startTime, 
                endTime;
            function touchFn(e) {
                e.preventDefault();
                switch (e.type) {
                    case 'touchstart':
                        startTime = new Date().getTime();
                        break;
                    case 'touchend':
                        endTime = new Date().getTime();
                        if(endTime - startTime < 200) {
                            handler.call(this,e)
                        }
                        break;  
                }
            }
        },
       
    window.myMobile = myMobile;

})(window)

上面代码意思是,两次时间间隔如果小于200ms,就触发传递进来的事件,可以代替点击事件来用。

html中引入fastClick.js文件

var ele = myMobile('#box11');
    ele.tab(function(e) {
    console.log('点击事件')
 })

点击事件被触发了,并且是⌚️小于300ms。这样就解决了300延迟问题。是不是很简单。

同理我们也可以增加长按事件,左右滑动,上下滑动事件。

(function(window) {
    'use stirct'
    function myMobile(selector) {
        return myMobile.prototype._init(selector)
    }
    myMobile.prototype = {
        _init: function(selector) {
            if (typeof selector === 'string') {
                this.ele = window.document.querySelector(selector);
                return this;
            }
        },
        // 单机事件
        tab: function(handler) {
            this.ele.addEventListener("touchstart", touchFn);
            this.ele.addEventListener("touchend", touchFn);
            var startTime, 
                endTime;
            function touchFn(e) {
                e.preventDefault();
                switch (e.type) {
                    case 'touchstart':
                        startTime = new Date().getTime();
                        break;
                    case 'touchend':
                        endTime = new Date().getTime();
                        if(endTime - startTime < 200) {
                            handler.call(this,e)
                        }
                        break;  
                }
            }
        },
        // 长按事件
        longTap: function(handler) {
            this.ele.addEventListener("touchstart", touchFn);
            this.ele.addEventListener("touchmove", touchFn);
            this.ele.addEventListener("touchend", touchFn);
            var timeId;
            function touchFn(e) {
                e.preventDefault();
                switch (e.type) {
                    case 'touchstart':
                        timeId = setTimeout(function() {
                            handler.call(this,e)
                        }, 500)
                        break;
                    case 'touchmove':
                        clearTimeout(timeId);
                        break; 
                    case 'touchend':
                        clearTimeout(timeId);
                        break;  
                }
            }
        },
        // 左侧滑动
        slide: function(fun) {
            this.ele.addEventListener("touchstart", touchFn);
            this.ele.addEventListener("touchend", touchFn);
            var startX, startY, endX, endY, moveLengthX, moveLengthY;

            function touchFn(e) {
                e.preventDefault();
                var firstTouch = e.changedTouches[0];
                switch (e.type) {
                    case 'touchstart':
                        startX = firstTouch.pageX;
                        startY = firstTouch.pageY;
                        break;
                    case 'touchend':
                        endX = firstTouch.pageX;
                        endY = firstTouch.pageY;
                        moveLengthX = Math.abs(endX - startX);
                        moveLengthY = Math.abs(endY - startY);
                        fun.call(this, moveLengthX,moveLengthY,e)
                        break;  
                }
            }
            
        },
    
        slideLeftRight: function(handler) {
            this.slide(function(moveLengthX, moveLengthY, e) {
                //  moveLengthX >= moveLengthY  确保是x轴的移动 
                if( moveLengthX >= moveLengthY && moveLengthX >= 25 ) {
                    handler(this, e);
                }
            });
           
        },
        slideTopBottom: function(handler) {
            this.slide(function(moveLengthX, moveLengthY, e) {
                if( moveLengthY >= moveLengthX && moveLengthY >= 25) {
                    handler(this, e);
                }
            });
            
        }
    }
    window.myMobile = myMobile;

})(window)

这里只是告诉你原理,实际操作的过程中,会发现左右滑动或者上下滑动太快的话会触发点击事件,所以不能同时使用,如果想知道怎么解决,可以去看fastClick.js的源码,里面有很多兼容性问题,也有很多事件追踪,可以解决上述问题。

 ele.longTap(function(e) {
  console.log('长按事件')
 })
 ele.slideLeftRight(function(e) {
   console.log('左右滑动事件')
 })
  ele.slideTopBottom(function(e) {
    console.log('上下滑动事件')
  })

有兴趣的可以去测试一下。代码都贴在这里了。

谷歌浏览器56个版本以后,阻止默认行为会报错

需要加一个样式解决这个问题

* {
    touch-action: none;
  }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值