0.0.2 • Published 3 years ago

umo-tap-scroll v0.0.2

Weekly downloads
-
License
ISC
Repository
-
Last release
3 years ago

tap-scroll

用于在 FastClick 环境下,各 WebView 进行 scroll 状态时手指按下阻止滚动时,阻止当次 click 事件的触发

Usage

npm install umo-tap-scroll

代码层只需新增 2 行

// 引用一下
import TapScroll from "umo-tap-scroll";
// 具体是直接 window.FastClick 还是 import 还是 require 随意,保证可以拿到FastClick符号即可
import FastClick from "fastclick";

// 加入一行解决
TapScroll.attachFastClick(FastClick);
// 业务本身就需要初始化
FastClick.attach(document.body);

lib/fix

fixTimeStamp

iOS 11.3+Chrome 49+Event.prototype.timeStamp 从时间戳(Date.now)变成了时间差(performance.now),提供了如下方法。

event传入handler前,将 timeStamp 赋值为时间戳,在handler处理完成后,还原成原来的样子

import { fixTimeStamp } from "umo-tap-scroll/lib/fix";
// 必须在首次 attach 之前执行fix逻辑
fixTimeStamp(FastClick);

fixPassive

iOS 11.3+,开始支持 PassiveEventListener

FastClickattachdestroy 阶段,使用 { passive: false } 来处理事件

import { fixPassive } from "umo-tap-scroll/lib/fix";
// 必须在首次 attach 之前执行fix逻辑
fixPassive(FastClick);

fixFocus

iOS 11.3+,FastClick 需要主动调用 target.focus 才能触发键盘的弹起

import { fixFocus } from "umo-tap-scroll/lib/fix";
// 必须在首次 attach 之前执行fix逻辑
fixFocus(FastClick);

Swiper 兼容

FastClick配合使用Swiper时,会有手指侧滑导致触发click的情况,可以按照如下方式做处理:

import TapScroll from "umo-tap-scroll";

new Swiper({
	...swiperOptions,
	onInit() {
		TapScroll.swiperOnInit();
	},
	onTap(swiper, event) {
		// 可能会 preventDefault
		TapScroll.swiperOnTap(swiper, event);
	},
	onTouchEnd(swiper, event) {
		// 可能会 preventDefault, stopPropagation
		TapScroll.swiperOnTouchEnd(swiper, event);
	},
});

测试验证

分别使用 UIWebView, WKWebView, U3, U4 打开http://site.alipay.net/h5-lib/tap-scroll/fastclick/,体验实际效果

  • meta + FastClick + target.scroll

使用 FastClick,并且 scroll 是通过overflow:scroll来实现的

  • meta + FastClick + window.scroll

使用 FastClick,并且 scroll 是在 window 上的

  • meta + TapScroll + target.scroll

使用 TapScroll,并且 scroll 是通过overflow:scroll来实现的

  • meta + TapScroll + window.scroll

使用 TapScroll,并且 scroll 是在 window 上的

  • meta + target.scroll

scroll 是通过overflow:scroll来实现的

  • meta + window.scroll

scroll 是在 window 上的

原理

300ms 浏览器支持程度

  • 可以通过meta避免的(<meta name="viewport" content="width=device-width;initial-scale=1.0;maximum-scale=1.0; user-scalable=no;">)
    • U4
    • U3
    • Chrome 33+
    • WKWebView
  • 必须依赖 FastClick 的 touch 机制
    • UIWebView

WKWebView 检测

  • 在支付宝内,检测 /\sWK\s/.test(navigator.userAgent)
  • 在支付宝外,检测 window.webkit.messageHandlers

attachFastClick 干了什么

不需要的

对可以通过 meta 避免的浏览器

  1. FastClick原生即支持 U3, U4, Chrome 32+
  2. 对于WKWebView, 在FastClick@1.0.6源码的基础上,重写了notNeeded函数,保证在支付宝钱包, Nebula容器WKWebView内核下工作不需要使用FastClick的机制,使用原生 click 事件

必须的

对必须依赖 FastClick 的 touch 机制的浏览器,目前仅针对UIWebView

  1. 对于UIWebView,在FastClick@1.0.6源码的基础上,重写了prototype.sendClick方法,当FastClick检测到touch事件,认为应该发送click时,拦截掉,根据一定逻辑,判断是否需要放行/阻止该模拟 click 事件

判断逻辑

UIWebView

根据以下scroll机制分析,如果把touchstart,touchend,scroll:window,scroll:target事件按照流的形式记录下来,可以有以下规律,只要检测事件流是否符合特定规律,符合即阻止当次 click 即可

st表示scroll:target

sw表示scroll:window

a表示touchstart

e表示touchend

对于在 target 上的 scroll

  • 滑动,无惯性,等停止点击:
    1. a-s-s-s-e----a-e ,返回 false
  • 滑动,惯性,等停止点击: 2. a-s-s-s-e---s----a-e,返回 false
  • 滑动,惯性,点击停止: 3. a-s-s-s-e-5-s----a-20-s-40-e 4. a-s-s-s-e-6-s----a-24-s-4-e 5. a-s-s-s-e-----a-17-s-8-e 6. a-s-s-s-e-----a-26-e-3-s 7. a-s-s-s-e----s-1-a---e 8. a-e-------a-s-e 返回 true

检测到Case 1,2认为是正常点击,检测到Case 3,4,5,6,7认为是滑动之后停止滑动,需要阻止掉

对于在 window 上的 scroll

  • 滑动,无惯性,等停止点击:
    1. a-e-8-s---a-e ,返回 false
  • 滑动,惯性,等停止点击: 2. a-e---s----a-e,返回 false
  • 滑动,惯性,点击停止: 3. a-e----a-e-s 4. a-e------s-a-e-s 5. a-s-e-------a-e-s 6. a-s-e-------a-s-e-s 返回 true

检测到Case 1,2认为是正常点击,检测到Case 3,4,5,6认为是滑动之后停止滑动,需要阻止掉

UIWebView 的 Scroll 机制

根据https://lark.alipay.com/hybrid/dev/uiwebview-stop-js该文档,分别对应着 2 种 scroll 方式,分别是,在 window 上做滚动,还有一种是在某个子元素上开启overflow: scroll做滚动,两种方式下的处理不太一致。

window
  • 手指按下滑动期间

js 不执行,scroll 事件不触发

  • 手指放开

    • 触发惯性滚动
    惯性滚动期间js不执行,scroll事件不触发

    惯性滚动结束时,js 执行,scroll 事件触发一次

    • 不触发惯性滚动,直接停止

    停止时开始执行 js,scroll 事件触发一次

target(子元素)
  • 手指按下滑动期间

js 执行

scroll 事件触发(间隔典型值 10-30ms)(如果手指不移动不触发,必须手指移动)

  • 手指放开

    • 触发惯性滚动(需要通过-webkit-overflow-scrolling: touch;开启)

    js 执行

    scroll 在惯性滚动停止时触发一次

    • 不触发惯性滚动,直接停止

    一切正常,由于上述 scroll 触发正常,此时不会特地触发一次 scroll

0.0.2

3 years ago

0.0.1

3 years ago