npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@whee/js-motion

v2.0.0

Published

motion for mobile

Downloads

3

Readme

Motion

Build Status codecov code style: prettier Commitizen friendly

移动端触摸手势检测工具,根据元素的 touchstart, touchmove, touchend 事件计算相关的滑动、缩放和旋转操作,以及触摸事件结束后的惯性滑动。

滑动、缩放以及旋转都是当前时刻相对元素上一时刻的状态计算的,因此从触摸开始(touchstart)到触摸结束(touchend)之间总的滑动距离和旋转角度,需要将每一时刻值进行累加,而缩放大小则需要累乘

示例

触摸板

使用

npm install @whee/js-motion

自动监听 options.target 元素的手势操作:

import Motion from '@whee/js-motion'

const motion = new Motion({
  target: '#target',
  mode: 'realtime',
  direction: 'xy'
})

motion.onTouchstart(e => {
  // ...
})
motion.onTouchmove(({ x, y, scale, angle }, e) => {
  // ...
})
motion.onTouchend(({ x, y }, e) => {
  // ...
})

如果已经进行了目标元素的 touch 事件绑定,则需要传入相关的事件,便可以检测到 event.target 元素的手势操作:

import Motion from '@whee/js-motion'

const motion = new Motion({
  mode: 'realtime',
  direction: 'xy'
})
const target = document.querySelector('#target')

target.addEventListener(
  'touchstart',
  e => {
    e.preventDefault()
    motion.touchstart(e)
    // 其他操作
    //...
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)

target.addEventListener(
  'touchmove',
  e => {
    e.preventDefault()
    motion.touchmove(e, ({ x, y, scale, angle }) => {
      // ...
    })
    // 其他操作
    // ...
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)

target.addEventListener(
  'touchend',
  e => {
    motion.touchend(e, ({ x, y }) => {
      // ...
    })
    // 其他操作
    // ...
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)

推荐使用第一种方式,motion 实例会自动监听 options.target 元素的相关事件。

Mode

touchmove 的执行模式:

  • 'realtime' - 实时模式:

    即每一次 touchmove 事件进行处理计算滑动距离。

  • 'frame' - 帧模式:

    即一帧内的多个 touchmove 事件合并,进行一次处理,计算总的滑动距离。

注意:如果可以尽量使用 realtime 模式,因为部分浏览器对 touchmove 事件触发的频率已经做了优化,使用 frame 会出现跨度较大的问题。

Direction

motion 监听的移动方向:

  • 'x' - 只监听水平方向的移动:

    只计算水平方向的移动距离,垂直方向的移动距离始终为 0。

  • 'y' - 只监听垂直方向的移动。

    只计算垂直方向的移动距离,水平方向的移动距离始终为 0。

  • 'xy' - 同时监听水平和垂直方向的移动。

    同时计算水平和垂直两个方向的移动距离。

Coordinate

参考的坐标系:

  • 'screen' - 使用 touch.screenXtouch.screenY 计算数据
  • 'client' - 使用 touch.clientXtouch.clientY 计算数据
  • 'page' - 使用 touch.pageXtouch.pageY 计算数据

Motion

const motion = new Motion(options)

实例化时指定 options.target 选项,被动监听 motion.touch

options

  • options.target - 需要监听触摸事件的目标元素,可选。
  • options.mode - 指定 touchmove 的执行模式,默认为 'realtime'
  • options.direction - 指定监听的移动方向,默认为 'xy'
  • options.coordinate - 参考的坐标系,默认为 'page'

motion.onTouchstart(cb)

监听 options.targettouchstart 操作,并将 touchstart 事件回调。

motion.onTouchstart(e => {
  // e 是 options.target 的 touchstart 事件
})

motion.onTouchmove(cb)

监听 options.targettouchmove 操作,并将滑动距离和 touchmove 事件回调。

motion.onTouchmove(({ x, y, scale, angle }, e) => {
  // x 是水平方向的移动距离
  // y 是垂直方向的移动距离
  // scale 是缩放比率
  // angle 是旋转的角度
  // e 是 options.target 元素的原生 touchmove 事件
})

motion.onTouchend(cb)

监听 options.targettouchend 操作,并将需要惯性滑动的距离和 touchend 事件进行回调。

回调的滑动距离为 0 时则表示滑动停止:

  • options.direction='x' - 回调惯性滑动距离分量 x0 时,表示惯性滑动停止
  • options.direction='y' - 回调惯性滑动距离分量 y0 时,表示惯性滑动停止
  • options.direction='xy' - 回调惯性滑动距离分量 xy 都为 0 时,表示惯性滑动停止

注意:如果没触发惯性滑动,只会触发一次回调;如果触发惯性滑动,则会进行多次回调,直到滑动停止。

motion.onTouchend(({ x, y }, e) => {
  // x 是水平方向的惯性移动距离
  // y 是垂直方向的惯性移动距离
  // e 是 options.target 元素的原生 touchend 事件
})

motion.touchstart(e)

实例化时没有指定 options.target 元素,则需要主动调用该方法,并传入 touchstart 事件,告诉 motion 实例滑动操作即将开始。

const target = document.querySelector('#target')

target.addEventListener(
  'touchstart',
  e => {
    // 主动传入 touchstart 事件,触摸开始
    motion.touchstart(e)
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)

注意:在调用 motion.touchmove() 之前始终需要先调用一次 motion.touchstart(),保证 motion 可以正确计算开始触摸的位置。

motion.touchmove(e, cb)

实例化时没有指定 options.target 元素,则需要主动调用该方法,并传入 touchmove 事件,告诉 motion 实例滑动操作正在进行。

const target = document.querySelector('#target')

target.addEventListener(
  'touchmove',
  e => {
    // 主动传入 touchmove 事件,正在滑动
    motion.touchmove(e, ({ x, y, scale, angle }) => {
      // x 是水平方向的滑动距离
      // y 是垂直方向的滑动距离
      // scale 是缩放比率
      // angle 是旋转的角度
    })
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)

motion.touchend(e, cb)

实例化时没有指定 options.target 元素,则需要主动调用该方法,并传入 touchend 事件,告诉 motion 实例触摸已经结束。达到惯性滑动条件,则会进行惯性滑动。

const target = document.querySelector('#target')

target.addEventListener(
  'touchend',
  e => {
    // 主动传入 touchend 事件,触摸结束
    motion.touchend(e, ({ x, y }) => {
      // x 是水平方向的惯性滑动距离
      // y 是垂直方向的惯性滑动距离
    })
  },
  Motion.isSupportPassive ? { passive: false, capture: true } : false
)