继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

关于移动端tap事件的实现

遥望星辰_
关注TA
已关注
手记 3
粉丝 27
获赞 74

在做移动端web开发时,常遇到click事件点击延迟问题,直接使用click事件就会造成不好的体验,但是我们可以用移动端的touch事件来模拟click事件,于是我花了些时间做了一个tap.js,下面附上代码。

js:

/*!
 * tap.js v1.2.2
*/
;(function (factory) {
    if (typeof define === 'function' && define.amd) {
        define(function(){return factory;});
    }else if (typeof exports == "object") {
        module.exports = factory;
    }else {
        window.tap = factory;
    }
}(function(){
    var arg = arguments,
        doc = window.document,
        els = arg[0] == doc ? [doc]:doc.querySelectorAll(arg[0]),
        isTouch = "ontouchend" in doc,
        len = els.length,
        i = 0,
        isEntrust = typeof arg[1]== 'string',
        isMulti = typeof arg[1]== 'object';

    if(len == 0){return false;}
    while (i < len){
        if(isTouch){
            var o = {};
            els[i].addEventListener('touchstart',function(e){
                var t = e.touches[0];
                o.startX = t.pageX;
                o.startY = t.pageY;
                o.sTime = + new Date;
            });
            els[i].addEventListener('touchend',function(e){
                var t = e.changedTouches[0];
                o.endX = t.pageX;
                o.endY = t.pageY;
                if((+ new Date)-o.sTime<300){
                    if(Math.abs(o.endX-o.startX)+Math.abs(o.endY-o.startY)<20){
                        handler(e,arg,this);
                    }
                }
                o = {};
            });
        }else{
            els[i].addEventListener('click',function(e){
                handler(e,arg,this);
            });
        }
        i ++;
    }
    function handler(e,arg,that){
        if(e.target.href){
            return window.location = e.target.href;
        }
        if(isEntrust){
            if(equal(e,arg[1])){
                prevent(e);
                arg[2].call(e.target,e);
            }
        }else if(isMulti){
            for(key in arg[1]){
                if(equal(e,key)){
                    prevent(e);
                    arg[1][key].call(e.target,e);
                    break;
                }
            }
        }else{
            prevent(e);
            arg[1].call(that,e);
        }
    }
    function equal(e,el){
        var flag = false;
        if(el.indexOf('.') != -1 && e.target.className == el.replace('.','')){
            flag = true;
        }else if(el.indexOf('#') != -1 && e.target.id == el.replace('#','')){
            flag = true;
        }else if(e.target.nodeName.toLocaleLowerCase() == el){
            flag = true;
        }
        return flag;
    }
    /*preventDefault不执行则会引起触发失效bug,
     *但不必要则不执行。 
    */
    function prevent(e){
        var tagName = e.target.tagName.toLocaleLowerCase();
        if(tagName != 'select' && tagName != 'input' && tagName != 'textarea'){
            doc.activeElement.blur();
            e.preventDefault();
        }
    }
}))

demo.html(这里可以直接运行测试)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1,maximum-scale=1.0, user-scalable=0">
    <title>tap demo</title>
    <style type="text/css">
        h4{margin: 10px 0;}
    </style>
</head>
<body>
        <h3>直接调用</h3>
    <div>
        <button class="button">tap1</button>
        <button class="button">tap2</button>
        <button class="button">tap3</button>
        <button class="button">tap4</button>
        <button class="button">tap5</button>
    </div>
    <hr>
    <h3>事件委托</h3>
    <div id="test">
        <button class="button2">tap1</button>
        <button class="add">add</button>
        <button class="doc">document</button>
    </div>
    <hr>
    <h3>事件冒泡</h3>
    <h4>正常冒泡</h4>
    <div id="parent">
        parent<br><br>
        <button class="son">son</button>
    </div>
    <h4>阻止冒泡</h4>
    <div id="parent2">
        parent2<br><br>
        <button class="son2">son2</button>
    </div>
    <h3>阻止默认动作</h3>
    <form action="">
        <button class="submit" type="submit">提交</button>
    </form>
    <h3>代码优化</h3>
    <h4>快速跳转</h4>
    <div class="a-box">
        <a href="https://github.com/weijhfly/tap"><button>里面有子元素</button></a>
        <a href="https://github.com/weijhfly/tap">没有子元素</a>
    </div>
    <br>
    <input type="text" placeholder="测试焦点是否正常">
    <h4>同时指定多个事件</h4>
    <button class="e1">事件1</button>
    <button class="e2">事件2</button>
    <button class="e3">事件3</button>
        <!-- layer.js仅做弹出演示 -->
    <script src="https://weijhfly.github.io/js/layer/layer.js"></script>
    <script src="https://weijhfly.github.io/js/tap.js"></script>
<script>
//直接调用
tap('.button',function(e){
    console.log(e);
    var event = "ontouchend" in document? 'tap':'click';
    layer.msg(event+' : '+this.innerText);
})
// 事件委托 event delegation
tap('#test','.button2',function(){
    var event = "ontouchend" in document? 'tap':'click';
    layer.msg(event+' : '+this.innerText);
})
var i = 0;
tap('#test','.add',function(e){
    console.log(e);
    i ++;
    var test = document.getElementById("test");
    var button = document.createElement("button");
    button.className = 'button2';
    button.innerHTML = "button "+i;
    test.insertBefore(button,test.childNodes[0]); 
})
tap(document,'.doc',function(){
    layer.msg('doc');
})
/*
阻止冒泡 stop propagation
在事件委托中仅能阻止委托元素对上层的冒泡
*/
tap('#parent',function(){
    setTimeout(function() {
        layer.msg('parent');
    }, 100);
})
tap('.son',function(){
    layer.msg('son');
})
// 阻止冒泡
tap('#parent2',function(){
    setTimeout(function() {
        layer.msg('parent2');
    }, 100);
})
tap('.son2',function(e){
    e.stopPropagation();
    layer.msg('son2');
})
/*
阻止默认动作
同上,事件委托中仅能阻止委托元素的默认动作
注意:在移动端默认执行e.preventDefault();
*/
tap('.submit',function(e){
    e.preventDefault();
    e.stopPropagation();
    layer.msg('无法提交');
})
/*
* 代码优化
*/
//跳转 **存在href属性
tap(document,'a');
// 通过委托实现多个事件 **默认不能重复,重复只执行第一个
tap(document,{
    '.e1':function(){
       layer.msg(this.innerText);
    },
    '.e2':function(){
       layer.msg(this.innerText);
    },
    '.e3':function(){
       layer.msg(this.innerText);
    }
});
</script>
</body>
</html>

github:https://github.com/weijhfly/tap
有兴趣的可以看下,另外还有vue v-tap指令版的https://github.com/weijhfly/vue-tap,欢迎关注。

此外,在移动端解决点击延迟问题,还是比较推荐fastclick,兼容性较好且方便使用,不过相对而言模拟tap事件体积较小,也可以拿来练手了。

打开App,阅读手记
1人推荐
发表评论
随时随地看视频慕课网APP