zoukankan      html  css  js  c++  java
  • 移动端的click

    移动端的click

    移动端click和touch的关系

    搬运 http://segmentfault.com/q/1010000000691822

    手指在屏幕上滑动时 各个touch的触发顺序
    touchstart
    touchmove
    touchcancel 滑动中突然有alert 或者其他情况导致滑动中断
    touchend

    关于轻拍tap(也就是单击) 触发的顺序是
    touchstart
    touchend
    mousemove
    mousedown
    mouseup
    click (300ms延迟才触发)

    为什么click延迟300ms

    移动端click是点一下触发 为什么会延迟300ms呢?
    首先需要的知道的是 click虽然是PC上针对鼠标的事件 但是在触摸屏上点一下 也会触发click事件

    不过移动端还有dbclick(双击放大页面)所以得有一个时间间隔来判断是单击还是双击

    PS
    http://am-team.github.io/amg/dev-exp-doc.html#click的300ms延迟响应

    在手机早期,浏览器有系统级的放大和缩小的功能,用户在屏幕上点击两次之后,系统会触发站点的放大/缩小功能。不过由于系统需要判断用户在点击之后,有没有接下来的第二次点击,因此在用户点击第一次的时候,会强制等待300ms,等待用户在这个时间内,是否有用户第二次的点击,如果没有的话,就会click的事件,否则就会触发放大/缩小的效果。

      $(function(){
        var msg = $('.msg');
        $('.title').tap(function(){
          msg.html(+new Date)
        });
        $('.title').click(function(){
          msg.html(msg.html() + '  '+ +new Date)
        });
      });
    

    用这个例子试一试就发现 click明显晚于tap

    在chrome 和 ff 的mobile版本中, 如果设置了页面禁止缩放 没有延迟
    比如设置了 <meta name="viewport" content="user-scalable=no">或者<meta name="viewport" content="width=device-width">
    在IOS上就有很明显的延迟

    那就用touchend?

    如果我们直接使用touchend事件来代替click事件,但这样副作用也很大,移动端的交互体验全靠触摸,touchstart将会干扰其他交互行为的处理,例如滚动、拖拽等, 也被认为是做了点击操作。

    另外一个问题即触发touchend事件后,在该区域300ms后还会触发一次click事件,(上面已经提到"轻拍" 所触发的事件顺序 其中是会触发click事件的)
    也就是穿透

    这样不合理

    用tap会带来穿透问题

    搬运
    http://www.cnblogs.com/chaojidan/p/4522986.html

    什么是穿透

    假如你在列表页面上创建一个弹出层,弹出层有个关闭的按钮(绑定了tap事件),你点了这个按钮关闭弹出层后,(且这个弹出层消失了) 这个个按钮正下方的内容也会执行点击事件(或打开链接)。这个就是一个“点透”现象。

    更详细的说
    重叠的区域里,被遮盖的元素绑定click,遮盖的元素绑定touch事件,且touch后遮盖的元素会隐藏的话,就会造成穿透,因为click是在touch之后延迟触发的,浏览器会误认为是在遮盖的元素上触发了click。

    为什么会穿透

    搬运
    http://www.qianduancun.com/javascript/38.html

    点了tap之后, 此时click事件还在延迟的300ms之中,当300ms到来的时候,click到的其实不是完成而是隐藏之后的下方的元素,如果正下方的元素绑定的有click事件此时便会触发,如果没有绑定click事件的话就当没click,但是正下方的是input输入框(或者select选择框或者单选复选框),点击默认聚焦而弹出输入键盘,也就出现了上面的点透现象。

    来个栗子感受一下 dialog是悬浮在input元素上的一个div

      $(function(){
        var msg = $('.msg');
        $('.title').tap(function(){
          msg.html(+new Date)
          $('.dialog').remove();
        });
        $('.input').click(function(){
          $('.input').text('clicked');
        });
      });
    

    zepto的tap事件

    首先tap并不是原生就有的事件 而是根据touchstart touchend的位置以及相隔时间综合判断而触发的一个事件

    zepto中 touchstart touchend绑定在了 body 上

    
        $(document.body).bind('touchstart', function(e){
          now = Date.now()
          delta = now - (touch.last || now)
          touch.el = $(parentIfText(e.touches[0].target))
    		//....
        }).bind('touchmove', function(e){
    		//...
        }).bind('touchend', function(e){
           cancelLongTap()
           //...
           // normal tap
          } else if ('last' in touch) {
            touch.el.trigger('tap')
    
            touchTimeout = setTimeout(function(){
              touchTimeout = null
              touch.el.trigger('singleTap')
              touch = {}
            },
          }
        });
    

    而click的触发是由机器决定的(或者说是机器模拟的click ) 为了消除这个300ms后才有的click 就有了fastclick

    fastclick

    FastClick 是 FT Labs 专门为解决移动端浏览器 300 毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick 在检测到 touchend 事件的时候,会通过 DOM 自定义事件立即触发一个模拟 click 事件,并把浏览器在 300 毫秒之后真正触发的 click 事件阻止掉。
    使用方式很简单

    window.addEventListener( "load", function() {
        FastClick.attach( document.body );
    }, false );
    
    

    fastclick实现

    搬运
    http://hao.jser.com/archive/8231/

    FastClick.prototype.onTouchEnd = function(event){
    
      // 一些状态监测代码 
    
      // 从这里开始,
      if (!this.needsClick(targetElement)) {
        // 如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click
        event.preventDefault(); 
        // 触发一次模拟的click
        this.sendClick(targetElement, event);
      }
    }
    

    模拟click事件

    FastClick.prototype.sendClick = function(targetElement, event) {
    
      // 这里是一些状态检查逻辑
    
      // 创建一个鼠标事件
      clickEvent = document.createEvent('MouseEvents');
      // 初始化鼠标事件为click事件
      clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
    
      // fastclick的内部变量,用来识别click事件是原生还是模拟
      clickEvent.forwardedTouchEvent = true;
    
      // 在目标元素上触发该鼠标事件,
      targetElement.dispatchEvent(clickEvent);
    

    在zepto上改造一下 , 约1336行的touchend事件中 在触发了tap之后

            e.preventDefault();
            var clickEvent = document.createEvent('MouseEvents');
            // 初始化鼠标事件为click事件
            //Pass in the options
            // event.initMouseEvent(
            //     opts.type,
            //     opts.canBubble,
            //     opts.cancelable,
            //     opts.view,
            //     opts.detail,
            //     opts.screenX,
            //     opts.screenY,
            //     opts.clientX,
            //     opts.clientY,
            //     opts.ctrlKey,
            //     opts.altKey,
            //     opts.shiftKey,
            //     opts.metaKey,
            //     opts.button,
            //     opts.relatedTarget
            // );
    
            clickEvent.initMouseEvent("click", true, true, window, 1, 0, 0, touch.x1, touch.y1, false, false, false, false, 0, null);
            clickEvent.forwardedTouchEvent = true;
            touch.el[0].dispatchEvent(clickEvent);
    
    

    改造后 在IOS中click事件 和tap约10ms差距(不同机器不同 PC只有5ms)
    并且点透的问题也OK了

  • 相关阅读:
    c++,不能声明为虚函数的函数
    Abstract
    多态性vptrvtable
    C++的重写,重载,重定义
    final
    scanf()和getchar() 使用
    深入理解C++中的mutable关键字
    equal和==
    MoQ(基于.net3.5,c#3.0的mock框架)简单介绍
    VS2008快捷键
  • 原文地址:https://www.cnblogs.com/cart55free99/p/4805596.html
Copyright © 2011-2022 走看看