Skip to content

shervinchen/any-touch

 
 

Repository files navigation

any-touch NPM Version NPM Downloads size-image codecov CircleCI

👋 一个小巧的手势库.

  • 更独立: 零依赖, 适合任意框架, 不限于vue/react/angular.
  • 更多端: PC 端 / 移动端 / 微信小程序.
  • 更全面: 支持Tap(点击) / Press(按压) / Pan(拖拽) / Swipe(快划) / Pinch(缩放) / Rotate(旋转)6种手势.
  • 更灵巧: 默认加载6个手势, 也可🤖按需加载手势, 核心@any-touch/core只有2kb, 完整安装也仅需要5kb.
  • 更简单: 在Vue可直接通过v-on调用, 比如<div @pan="onPan"></div>.
  • 更放心: 代码测试覆盖率100%.

演示

查看二维码

直接访问

目录

⚡ 快速开始

🌱 兼容vue语法

📱 支持微信小程序

🤖 按需加载

💡 API

🍭 事件对象(event)

❗❗❗ 注意事项

安装

npm i -S any-touch

CDN

https://unpkg.com/any-touch/dist/any-touch.umd.min.js

快速开始

import AnyTouch from 'any-touch';
const el = doucument.getElementById('box');
const at = new AnyTouch(el);
// 单击
at.on('tap', (ev) => {
    // ev包含位置/速度/方向等信息
});

返回目录

兼容vue语法

<div 
    @tap="onTap" 
    @swipe="onSwipe" 
    @press="onPress" 
    @pan="onPan" 
    @pinch="onPinch" 
    @rotate="onRotate">
    <p>Hello any-touch</p>
</div>
import AnyTouch from 'any-touch';
export default {
    mounted() {
        // 没错, 就这2行
        const at = new AnyTouch(this.$el);
        this.$on('hook:destroyed', ()=>{
            at.destroy();
        });
    }
};

注意 由于框架(vue等)的特殊行, 建议多触点手势(pinch/rotate等pointLength>1的手势)使用match, 如<div @pinch="$event.match() && onPinch"></div>, 用来保证每个触点都落在目标元素内(使用anyTouch.target().on()监听不需要考虑这个问题.

返回目录

支持微信小程序

由于微信小程序中没有 dom 元素的概念, 所以我们需要通过catchEvent方法手动接收 touch 事件的事件对象来进行识别!

<view 
  @touchstart="onTouchstart"
  @touchmove="onTouchmove"
  @touchend="onTouchend"></view>
const at = new AnyTouch()
{
    onload(){
        at.on('press', ev=>{
            // 按压
        });
    },

    methods: {
      onTouchstart(ev){
        at.catchEvent(ev);
      },
      onTouchmove(ev){
        at.catchEvent(ev);
      },
      onTouchend(ev){
        at.catchEvent(ev);
      }
    }
}

返回目录

target(事件委派)

如果有多个元素需要绑定手势, 那么建议初始化绑定一个父元素, 通过target绑定子元素和函数.

const at =  new AnyTouch(parent);
at.on('pan', onPan, { target: child });
// 还可以表示为
at.target(child).on('pan', onPan);

返回目录

beforeEach(触发拦截)

beforeEach拦截手势的触发, 用来实现同类手势不同时触发. 比如"双击"明显不能同时触发2次"单击", 所以我们需要让"单击"出发后延迟300ms, 如果没有触发"双击", "单击"再触发.

import AnyTouch from '@any-touch/core';
import Tap from '@any-touch/tap';
import {STATUS_POSSIBLE, STATUS_FAILED} from '@any-touch/shared';
import debounce from 'lodash/debounce'
AnyTouch.use(Tap);
AnyTouch.use(Tap, { name: 'doubletap', tapTimes: 2 });
const at = new AnyTouch(el);

// 🚀关键代码
// 单击后延迟300ms, 如果双击没有触发才触发单击
// 这里通过next来控制触发时机
at.beforeEach(({ recognizerMap, name }, next) => {
    if ('tap' === name) {
        debounce(() => {
            if ([STATUS_POSSIBLE, STATUS_FAILED].includes(recognizerMap.doubletap.status)) next();
        }, 300);
    } else {
        next();
    }
});

at.on('tap', onTap);
at.on('doubletap', onDoubleTap);

"next"的执行用来决定是否触发对应事件. 说到这里顺便解释下手势识别器的状态:

手势识别器的状态

变量 说明
STATUS_POSSIBLE 表示当前还"未识别"
STATUS_START "拖拽类"手势(pan/pinch/rotate等)中表示"第一次识别."
STATUS_MOVE "拖拽类"手势中表示"识别后移动中"
STATUS_END "拖拽类"手势中表示"有触点离开,即手势结束"
STATUS_CANCELLED 手势识别后,发生事件中断,比如"来电话","浏览器最小化"等.
STATUS_FAILED 表示"识别失败", 比如识别tap的时候,触点在250ms内没有离开屏幕等
STATUS_RECOGNIZED 表示"已识别", 区别于"拖拽类"手势, 用在"瞬发"识别的手势,比如tap/press/swipe.

按需加载

默认any-touch支持所有手势, 为了减小"体积"和"不必要的识别器执行时间", 提供了按需加载.

使用"按需加载"

⚠️ 注意: 执行npm i any-touch后, "@any-touch/core"和"@any-touch/xx手势"🤖便已自动安装, 直接引入即可.

// 只加载pan识别器(拖拽)
import Core from '@any-touch/core';
import Pan from '@any-touch/pan';
// 使用Pan
Core.use(Pan);
const at = new Core(el);
// 拖拽
at.on('pan', (ev) => {
    // ev包含位置/速度/方向等信息
});

@any-touch/core

手势库的核心组件, 主要用来把Mouse/Touch输入变成统一的输出, 实现PC/Mobile端的兼容, 提供了"at:"开头的兼容事件.

import Core from '@any-touch/core';
const at = new Core(el);
// 兼容Mouse/Touch
at.on('at:touch', (ev) => {
    // ev包含位置/时间/事件对象等属性.
});
// touchstart 或 mousedown
at.on('at:touchstart', onStart);
// touchmove 或 mousemove
at.on('at:touchmove', onMove);
// touchend 或 mouseup
at.on('at:touchend', onEnd);
// touchcancel
at.on('at:touchcancel', onCancel);

@any-touch/xx手势

手势识别器均已做成独立的包, 从而实现按需加载.

名称 说明
@any-touch/tap 点击
@any-touch/pan 拖拽
@any-touch/swipe
@any-touch/press 按压
@any-touch/pinch 缩放
@any-touch/rotate 旋转

⚠️ 再次提示: 如果已安装"any-touch", 上面的包便也已经自动安装.

返回目录

注意事项

手势识别器的name字段必填

自定义手势一定记得给起一个名字哦, 而且不要和默认存在的手势同名(已有tap/swipe/pan/rotate/pinch/press).

AnyTouch.use(Tap, { pointLength: 2 , name:'twoFingersTap'});
at.on('twoFingersTap', onTwoFingersTap);

不要用 alert 调试

❗❗❗ 在安卓手机的真机上, 如果touchstarttouchmove阶段触发了alert, 会出现后续的touchmove/touchend不触发的 bug. 所以请大家务必避免在手势的事件回调中使用alert. 测试代码

如果仅仅是了在移动端调试, 请使用腾讯的vconsole

macos上的chrome浏览器触发touchend会比较慢

由于上述原因, swipe事件发生的会"慢半拍",所以请大家最终测试以手机效果为准.

返回目录

About

👋 手势库, 按需2kb~5kb, 支持PC / 手机 / 微信端.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • TypeScript 74.6%
  • Vue 15.8%
  • JavaScript 9.0%
  • HTML 0.6%