zoukankan      html  css  js  c++  java
  • 移动端点击、触碰

    这篇文章将会阐述以下问题

    1. 延迟的click

    2. 拥抱tap

    3. 一次触碰

    4. 阻止它们!!!preventDefault还是stopPropagtion

    5. 模拟事件是什么鬼

    事故现场

    1. 延迟

    2. 点穿(包含angular的ng-click)

    3. 焦点获取

    分析Yocto,zepto,fastclick带来的思考

    1. zepto -- 万恶的tap

    2. fastclick -- “完美”

    3. Yocto -- “后zepto时代替代者”

    让我们开始吧!

    迟到的click

    “移动端最好用tap,click是有延迟的...”

    开始写移动端事件的时候就被告知了这一句真理,一直也没放在心上,tap就tap吧。 但是突然有一天很无聊,想要看看,到底为什么click有延迟,延迟多少。

    我们先来看两张图

    移动端点击、触碰随记

    移动端点击、触碰随记

    *这里的数据可能不准,因为多次点击的时间会不同,但是大概也就这样-_-# 这里注意到

    1. click的时间基本固定在301ms

    2. tap的时间会有点飘忽,差不多70-150ms左右。

    为什么要给出这样的数据呢,是为了印证click确实是比tap慢的。网上基本比较一致的原因是:

    "iphone创建了双击缩放的标准,背后的实现是,在第一次的点击时等待300ms,确定下一次是否继续点击。然后被众多移动端浏览器商家纷纷模仿 -----我乱说的"

    这就是click有300ms延迟的原因

    既然我们知道了是由于缩放引起的延迟,那么我们加入熟悉的

    <meta name="viewport" content="width=device-width user-scalable=no">

    再看一下数据,发现延迟果然没有了,速度和tap一毛一样(真是睁着眼说瞎话啊...)。

    移动端点击、触碰随记

    然而user-scalble=no 是非常邪恶的东西,我们不能光靠这个去解决问题,因此我们需要拥抱新同学tap...

    新同学tap

    tap事件运用最多莫过于zepto啦。看一片zepto的源码好了。

    移动端点击、触碰随记

    这片代码位于zepto.js最底部,因为篇幅缩短了swiper和dbclick的判断,但是可以看出,tap是基于touchstart和touchend模拟的(应该说别无他法)。

    这就是tap比click快的原因

    一次触碰

    由于历史原因,因此在移动端进行触碰的时候,也会触发鼠标的事件。这里给出测试结果。 触发的顺序是:

    • touchstart

    • touchmove

    • touchend

    • mouseover

    • mouseenter

    • mousedown

    • click

    整个触碰过程中,从touchstart开始,到click终结。

    可以看出tap和click的本质上其实只是触碰的不同阶段。

    阻止它们!preventDefault还是stopPropagation

    既然zepto可以自己创建一个tap事件,我们是不是也可以呢。考虑再三,难点在于怎么将上面控制一次触碰的流程,由于不知道这些事件是具有上下级(是否冒泡) 还是 传递性质。 (后来发现自己脑洞略大,为什么会这么想呢...TAT)

    在web端,preventDefault最常用的场景莫过于 a链接submit按钮 。 因为preventDefault的定义是

    “取消事件的默认行为。如果cancelable是true,则可以使用这个方法。”

    而stopPropagation的定义是

    “取消事件的进一步捕获或冒泡,如果bubbles为true,则可以使用这个方法。”

    那么在移动端,如果想要改变一次触碰的的流程,到底是阻止默认行为,还是冒泡呢。

    这里上一个demo的截图

    移动端点击、触碰随记

    经过测试,发现stopPropagation并不能阻止click的触发,而preventDefault被证实在确实是无解的大招

    这里插入一个知识点:stopImmediatePropagation是一个很屌的方法,不仅能够阻止事件冒泡,而且能够阻止绑定在同一个[事件名称]上的所有后续事件触发。

    stopImmeadiatePropagation的demo传送门

    阻止移动端的触碰默认行为。preventDefault是有着绝对的作用的。

    模拟事件是什么鬼

    在web端模拟一个事件已经是很成熟啦,好处一堆,便于测试,分离代码,组件化等等...我们是否能够应用在移动端呢。 先看到模拟事件分为以下四种

    • UIEvents

    • MouseEvents

    • MutationEvents

    • HTMLEvents

    流程大概分为

    1. 创建Event

    2. 初始化Event

    3. 触发Event

    触发之后就和正常流程触发的事件别无二致啦。这里给出一个<<高级编程>>的典型点击demo。后面我们要用到这个demo去做一些很酷的事情!

    移动端点击、触碰随记

    事故现场

    延迟

    前面说过了,点击延迟主要因为不确定是否进行缩放导致的,但是user-scalable并不是什么灵丹妙药,于是我们拥抱了tap,用touch-starttouch-end模拟了一个轻触tap事件,使得点击看起来快速了很多。典型代表就是zepto的tap事件。

    解决方案:

    假如应用场景不复杂(没有滑动,获取焦点),我们可以非常简单模拟一个阉割版的点击,而且也同时避免了点穿。如图

    移动端点击、触碰随记

    点穿

    大部分用zepto的同学一定踩过这个坑。

    “zepto居然把事件都绑定在document上!这太坑了。”

    呵呵,反正踩完坑就开始一顿乱喷,但是问题还是没有解决,如果要简单解决单纯的点击和上面一样,加上霸道的e.preventDefault()阻止默认事件传递就好了。但是我们用zepto还用了swiper,阉割版的做法还会导致一系列问题。于是乎号称完美的fastclick闪亮登场了。

    但是一样是把事件绑定在document上,为什么fastclick就不坑了呢。

    呵呵。

    解决方案:

    1. fastclick (FT Labs,目前GitHub已经10000星星了.....)

    2. Yocto(基于zepto的支付宝移动端库)

    3. 模拟fastclick做法,加入到自己豪华午餐里^_^

    然而

    在使用angular的时候,无可避免一定会用到ng-click

    (谁说无可避免,不是还有ng-touch这样的类库吗 逃...)

    那么不用类库,直接了当解决ng-click点穿怎么是好。

    然而-解决方案:

    古语有云:用angular的都是屌丝,屌丝一般都用了user-scalable=no,所以click速度不担心...

    只需要在ng-click=fn($event),传入event就又可以使用大招event.preventDefault

    然而更合理的做法应该是这样的。

    移动端点击、触碰随记

    传送门:关于angular自定义touchstart无效的解决办法

    事已至此,点穿就解决了。(啦啦啦啦啦啦啦)

    焦点获取

    点穿之后,无非就是焦点获取错误或者触发了其他表单元素,所以我们也必须处理一下这些边角料。

    这里列一下坑

    • textarea 需要focus

    • selct (这个天坑啊 android需要click IOS需要focus)

    • input (file,image,radio,checkbox) 需要click

    • label (*一般不操作,但是友好的做法是聚焦到对应的input)

    因此做法是,设置一个标志量needFocus,在触碰的过程中判断target是否为需要focus的,是就取消点击,改为聚焦

    1、获取target类型

    target.nodeName.toLowerCase();2、聚焦

    target.focus()3、聚焦在label对应的input

    document.getElmentById(labelElement.htmlFor).focus()

    fastclick

    这里简单说一下fastclick的解决点穿的原理

    1. fastclick绑定在document.body上,检查一次触碰的所有事件

    2. 用touchstart-touchend模拟了tap,而是在阻止真实的click触发后,模拟了真实click点击对象上。从而快速又完整的完成一次点击,并且不点穿。

    3. fastclick依然对双击事件做了保留,做法是,在touchend判断是否处于上次点击的时间范围内(fastclick出的是200ms)

    4. fastclick没有放弃swipe,中间加入了touchmove,使用了移动的范围(fastclick给出的是10)来判断是否进行滑动。

    5. fastclick对labelselect做了非常细致的处理(万星项目呢,开玩笑呢!)

    上面说的很复杂,伪代码表示一下

    var lastClickTime,trackClick; // 上一次点击时间,和是否追踪点击btn.bind("touchstart",function(e){

    // 判断是否用户快速双击事件,如果是,禁止本次触碰后续操作(包括模拟点击事件) trackClick = true;

    if(e.timeStamp - lastClickTime < 200){

    e.preventDefault();

    } },false);btn.bind("touchmove",function(e){

    // 判断是否移动过大导致偏移原标 或者 移动超出一定范围(这里是) if(moveToAnotherTarget || moveTooMuch){

    trackClick = false;

    }},false);btn.bind("touchend",function(e){

    // 依然进行是否[追踪]和[双击]判断,这里省略...

    // 这里判断进行[焦点]还是[下拉菜单]还是需要[点击] // 这里按照点击来进行,先禁用原生的点击,再把模拟的点击事件发送给当前目标 e.preventDefault();

    // 这里就是模拟事件发挥的地方了 e.target.dispatch(mouseClickEvent);},false);

    其实fastclick的核心就是[e.preventDefault阻止真实click][分发模拟鼠标事件的click]。#我乱说的#

    Yocto

    虽然名为支付宝下的[超轻]移动类库,这里还是想像成一个维护快速的zepto会比较好。 做法和fastclick一样。看一下他们更新的issue#

    移动端点击、触碰随记

    那既然有fastclick,为什么要看Yocto呢。

    1、 zepto+fastclick显得很没必要2、 [轻]可以独立引用yocto-event.js3、 基于zepto,学习成本低

    传送门:yocto对于修改zepto的最佳实践

    目前这个项目的gitlab外人时看不到的,所以只能等待他们完全开源了,之前看无线的移动端优化建议曾经提到,因此留心了一下,出来之后又可以猛偷了...(读书人的事情怎么能叫偷 逃...)

    到这里,差不多刚好20分钟,文章也结束了。

    ps:FastClick源码比较短,这里简单做个引读好了,希望不要误人子弟(掩面...

    fastclick = {

    标志变量, // 一堆辅助判断触碰类型的变量

    核心方法:{ // 这些就是核心精华啊...10000个星星都在这里了 onTouchStart

    onTouchMove

    onTouchEnd

    onClick

    onMouse

    focus }

    用户定义方法:{

    needClick, // 用户决定最终行为 needFocus // 用户决定最终行为 }

    难点:{

    updateScrollParent,// 对滑动进行了细致的兼容,实现比较复杂 stopImmediate方法 // 对不兼容此方法的环境改变了事件定义方式 }}

    参考文章:

    移动端页面touch会穿透,这是bug么?

    yocto的点穿demo

    彻底解决tap“点透”,提升移动端点击响应速度

    用bootstrap的同学,手机点击问题:
    不少朋友反馈在手机浏览器中无法点击下拉菜单的链接,搜索了一番,打开 bootstrap.min.js,查找到 ontouchstart ,替换为 disable-ontouchstart 就可以了。

  • 相关阅读:
    leetcode 268. Missing Number
    leetcode 189. Rotate Array
    leetcode 118. Pascal's Triangle 、119. Pascal's Triangle II 、120. Triangle
    HDU高精度总结(java大数类)
    一起talk C栗子吧(第八十七回:C语言实例--使用管道进行进程间通信概述)
    iOS敏捷开发之道,经常使用的宏定义总结
    360 网络攻防 hackgame 解题报告(通关)
    打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
    数列求和
    指尖上的电商---(11)Windows平台部署SolrCloud
  • 原文地址:https://www.cnblogs.com/qiuzhimutou/p/4762754.html
Copyright © 2011-2022 走看看