移动端点击、触碰

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

  1. 延迟的clickhtml

  2. 拥抱tapnode

  3. 一次触碰android

  4. 阻止它们!!!preventDefault仍是stopPropagtiongit

  5. 模拟事件是什么鬼web

事故现场编程

  1. 延迟bootstrap

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

  3. 焦点获取iphone

分析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的,是就取消点击,改成聚焦

一、获取target类型

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

target.focus()三、聚焦在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呢。

一、 zepto+fastclick显得很不必二、 [轻]能够独立引用yocto-event.js三、 基于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 就能够了。

相关文章
相关标签/搜索