use-gesture官方文档详解:从入门到精通
引言
你还在为实现流畅的触摸和鼠标手势交互而烦恼吗?use-gesture是一个功能强大的JavaScript库,它能帮助你轻松地为React和Vanilla JavaScript应用添加丰富的手势支持。无论是拖拽、缩放、滑动还是旋转,use-gesture都能提供简洁而强大的API,让你的应用交互体验提升到新的水平。
读完本文,你将能够:
- 了解use-gesture的核心概念和架构
- 掌握在React和Vanilla JavaScript中使用各种手势的方法
- 学会配置手势选项以满足特定需求
- 解决常见的手势交互问题
- 探索实用的示例和最佳实践
什么是use-gesture?
use-gesture是一个轻量级的手势库,它允许你将鼠标和触摸事件绑定到任何组件或元素上。通过提供丰富的手势数据,use-gesture使得实现复杂的交互效果变得简单,通常只需几行代码。

use-gesture最初是为React构建的,但从v10版本开始,它已经成为平台无关的库,可以在Vanilla JavaScript中使用。你可以将其单独使用,也可以与动画库(如react-spring)结合使用,以创建更加流畅的交互体验。
官方文档:documentation/pages/docs/introduction.mdx 项目源码:packages/ 项目教程:README.md
安装与基本使用
安装
use-gesture提供了两个包:一个用于React,一个用于Vanilla JavaScript。
React安装:
# Yarn
yarn add @use-gesture/react
# NPM
npm install @use-gesture/react
Vanilla JavaScript安装:
# Yarn
yarn add @use-gesture/vanilla
# NPM
npm install @use-gesture/vanilla
基本示例
React示例:
import { useSpring, animated } from '@react-spring/web'
import { useDrag } from '@use-gesture/react'
function PullRelease() {
const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
// 设置拖动钩子并根据手势数据定义组件移动
const bind = useDrag(({ down, movement: [mx, my] }) => {
api.start({ x: down ? mx : 0, y: down ? my : 0, immediate: down })
})
// 将其绑定到组件
return <animated.div {...bind()} style={{ x, y, touchAction: 'none' }} />
}
Vanilla JavaScript示例:
<!-- index.html -->
<div id="drag" />
// script.js
const el = document.getElementById('drag')
const gesture = new DragGesture(el, ({ active, movement: [mx, my] }) => {
setActive(active)
anime({
targets: el,
translateX: active ? mx : 0,
translateY: active ? my : 0,
duration: active ? 0 : 1000
})
})
// 当你想移除监听器时
gesture.destroy()
这个简单的例子创建了一个可拖动的元素,它会跟随鼠标或触摸移动,并在释放时返回初始位置。
重要提示:在可拖动元素上,你应该始终使用CSS属性
touch-action: none,以防止在触摸设备上与浏览器原生滚动发生冲突。
支持的手势类型
use-gesture提供了多种手势钩子(React)和类(Vanilla),以处理不同类型的用户交互。
React手势钩子
| 钩子名称 | 描述 |
|---|---|
useDrag | 处理拖拽手势 |
useMove | 处理鼠标移动事件 |
useHover | 处理鼠标进入和离开事件 |
useScroll | 处理滚动事件 |
useWheel | 处理鼠标滚轮事件 |
usePinch | 处理捏合手势(缩放和旋转) |
useGesture | 在一个钩子中处理多种手势 |
Vanilla JavaScript手势类
| 类名称 | 描述 |
|---|---|
DragGesture | 处理拖拽手势 |
MoveGesture | 处理鼠标移动事件 |
HoverGesture | 处理鼠标进入和离开事件 |
ScrollGesture | 处理滚动事件 |
WheelGesture | 处理鼠标滚轮事件 |
PinchGesture | 处理捏合手势(缩放和旋转) |
Gesture | 在一个类中处理多种手势 |
手势源码:packages/core/src/engines/
手势状态
每次手势处理器被调用时,它都会收到一个手势状态对象,其中包含源事件和多个附加属性,如速度、先前值等。
通用手势状态属性
const bind = useDrag(state => {
const {
event, // 源事件
xy, // [x,y] 值(指针位置或滚动偏移)
initial, // 手势开始时的xy值
intentional, // 手势是否是有意的
delta, // 移动增量(当前移动 - 上一次移动)
offset, // 自第一次手势以来的偏移量
lastOffset, // 上一次手势开始时的偏移量
movement, // offset与lastOffset之间的位移
velocity, // 手势在每个轴上的动量(以px/ms为单位)
distance, // 每个轴上的偏移距离
direction, // 每个轴上的方向
overflow, // 偏移是否超出边界(每个轴)
startTime, // 手势开始时间(ms)
timeDelta, // 与上一个事件的时间差(ms)
elapsedTime, // 手势经过的时间(ms)
timeStamp, // 事件的时间戳
type, // 事件类型
target, // 事件目标
currentTarget, // 事件当前目标
first, // 是否是第一个事件
last, // 是否是最后一个事件
active, // 手势是否处于活动状态
memo, // 处理器上一次运行返回的值
cancel, // 可以调用以中断某些手势的函数
canceled, // 手势是否被取消(拖拽和捏合)
down, // 鼠标按钮或触摸是否按下
buttons, // 按下的按钮数量
touches, // 触摸屏幕的手指数量
args, // 传递给bind的参数(仅React)
ctrlKey, // Ctrl键是否按下
altKey, // Alt键是否按下
shiftKey, // Shift键是否按下
metaKey, // Meta键是否按下
locked, // document.pointerLockElement是否设置
dragging, // 组件当前是否被拖拽
moving, // 组件当前是否被移动
scrolling, // 组件当前是否被滚动
wheeling, // 组件当前是否被滚轮操作
pinching // 组件当前是否被捏合
} = state
})
捏合手势特有属性
捏合手势的状态属性包括上述所有属性(除了xy和vxvy),并添加了以下属性:
const bind = usePinch(state => {
const {
da, // 两个指针的绝对距离和角度 [distance, angle]
origin, // 两个触摸事件之间的中心点坐标
offset, // [scale, angle] 偏移量(以scale=1开始)
} = state
})
拖拽手势特有属性
拖拽手势状态添加了一些有助于理解用户意图的属性:
const bind = useDrag(state => {
const {
swipe, // [swipeX, swipeY] 如果未检测到滑动则为0,否则为-1或1
tap, // 拖拽是否被识别为点击
} = state
})
状态类型定义:packages/core/src/types/state.ts
手势配置选项
use-gesture提供了多种选项来配置手势行为。这些选项可以分为共享选项和特定手势选项。
配置对象结构
根据你使用的是特定手势钩子还是useGesture钩子/Gesture类,配置对象的结构会有所不同。
React示例:
// 使用特定手势钩子时
useDrag((state) => doSomethingWith(state), { ...sharedOptions, ...dragOptions })
// 使用useGesture钩子时
useGesture(
{
onDrag: (state) => doSomethingWith(state),
onPinch: (state) => doSomethingWith(state)
// ...
},
{
// 全局选项,如`target`
...sharedOptions,
// 特定手势选项
drag: dragOptions,
wheel: wheelOptions,
pinch: pinchOptions,
scroll: scrollOptions,
hover: hoverOptions
}
)
常用配置选项
| 选项名称 | 适用手势 | 描述 |
|---|---|---|
enabled | 所有 | 是否启用手势 |
axis | 坐标类 | 限制手势只能在指定轴上触发('x'、'y'、'lock'或undefined) |
threshold | 所有 | 手势位移必须大于此阈值才会触发处理器 |
bounds | 坐标类 | 将手势偏移限制在指定边界内 |
from | 所有 | 指定偏移量的起始位置 |
preventDefault | 所有 | 是否阻止事件的默认行为 |
touchAction | 拖拽 | CSS touch-action属性,用于优化触摸设备上的交互 |
filterTaps | 拖拽 | 是否过滤点击事件,区分点击和拖拽 |
swipe.distance | 拖拽 | 触发滑动所需的最小距离 |
swipe.velocity | 拖拽 | 触发滑动所需的最小速度 |
示例:限制拖拽边界
const bind = useDrag(
({ offset: [ox, oy] }) => api.start({ x: ox, y: oy }),
{ bounds: { left: -100, right: 100, top: -50, bottom: 50 } }
)
示例:设置滑动检测阈值
const bind = useDrag(
({ swipe }) => {
if (swipe[0] !== 0) {
console.log('水平滑动:', swipe[0] === 1 ? '右' : '左')
}
},
{ swipe: { distance: 50, velocity: 0.5 } }
)
完整选项说明:documentation/pages/docs/options.mdx
高级用法
同时处理多种手势
use-gesture允许你在同一个组件上同时处理多种手势。例如,你可能希望在同一个组件上启用拖拽和捏合手势。
import { useGesture } from '@use-gesture/react'
const bind = useGesture({
onDrag: (state) => handleDrag(state),
onPinch: (state) => handlePinch(state),
onWheel: (state) => handleWheel(state),
// 其他手势...
}, {
drag: { axis: 'x' },
pinch: { scaleBounds: { min: 0.5, max: 3 } },
wheel: { preventDefault: true }
})
return <div {...bind()} />
自定义手势识别器
如果你只需要使用部分手势,可以创建自定义的手势识别器,以减小 bundle 体积。
import { createUseGesture, dragAction, pinchAction } from '@use-gesture/react'
// 只包含拖拽和捏合手势
const useGesture = createUseGesture([dragAction, pinchAction])
const bind = useGesture({
onDrag: (state) => doSomethingWith(state),
onPinch: (state) => doSomethingWith(state)
}, {
drag: dragConfig,
pinch: pinchConfig
})
return <div {...bind()} />
自定义手势源码:packages/react/src/createUseGesture.ts
使用ref绑定手势
在某些情况下,你可能需要将手势绑定到不是直接子组件的元素上。这时可以使用target选项和React ref。
import { useRef } from 'react'
function RefExample() {
const ref = useRef()
const bind = useDrag((state) => doSomethingWith(state), { target: ref })
return (
<div>
<div ref={ref}>这个元素会接收手势事件</div>
<div>这个元素不会</div>
</div>
)
}
实际示例
use-gesture可以用于创建各种复杂的交互效果。以下是一些常见的示例:
1. 可拖拽列表

这个示例展示了如何创建一个可拖拽排序的列表。关键在于使用拖拽手势的offset和args属性来跟踪每个列表项的位置变化。
源码示例:demo/src/sandboxes/draggable-list/
2. 卡片堆叠

这个示例展示了一个类似Tinder的卡片堆叠交互,使用拖拽手势的direction和velocity属性来判断卡片的滑动方向和速度,从而决定卡片是被接受还是拒绝。
源码示例:demo/src/sandboxes/cards-stack/
3. 无限轮播

这个示例结合了拖拽和滚轮手势来创建一个无限轮播组件。使用movement属性来跟踪滑动距离,使用wheel事件来响应用户的滚轮操作。
源码示例:demo/src/sandboxes/infinite-slideshow/
更多示例:documentation/pages/docs/examples.mdx
常见问题与解决方案
Q: 如何区分点击和拖拽事件?
A: 使用filterTaps选项可以帮助区分点击和拖拽。当设置filterTaps: true时,轻微的点击不会触发拖拽逻辑,并且state.tap会在点击时为true。
const bind = useDrag(
({ tap, down, movement }) => {
if (tap) {
console.log('点击事件')
} else if (down) {
console.log('拖拽中', movement)
}
},
{ filterTaps: true }
)
Q: 如何在移动设备上防止页面滚动?
A: 使用CSS的touch-action属性可以优化触摸设备上的交互。例如,touch-action: pan-y允许垂直滚动,但阻止水平滚动,这在处理水平拖拽时很有用。
return <div {...bind()} style={{ touchAction: 'pan-y' }} />
Q: 为什么我的拖拽元素在移动设备上响应迟缓?
A: 这可能是因为没有正确设置touch-action属性,导致浏览器的默认触摸行为与你的拖拽逻辑冲突。确保为拖拽元素设置touch-action: none。
.draggable-element {
touch-action: none;
user-select: none; /* 可选,防止文本选择 */
}
更多常见问题:documentation/pages/docs/faq.mdx
性能优化
使用事件委托
对于大量相似元素(如列表项),使用事件委托可以提高性能。use-gesture的target选项允许你将事件监听器附加到父元素,而不是每个子元素。
避免不必要的渲染
当使用React时,尽量避免在手势处理器中触发不必要的渲染。可以使用useCallback记忆化处理器函数,或使用react-spring等动画库直接操作DOM,而不经过React的渲染周期。
合理设置阈值
为手势设置适当的threshold可以防止微小的无意移动触发手势逻辑,提高用户体验并减少不必要的计算。
总结
use-gesture是一个功能强大且灵活的手势库,它简化了在React和Vanilla JavaScript应用中实现复杂手势交互的过程。通过提供丰富的手势数据和可配置的选项,use-gesture使开发者能够轻松创建流畅、自然的用户交互。
无论是简单的拖拽功能还是复杂的多点触控操作,use-gesture都能满足你的需求。其简洁的API设计和详细的文档使学习和使用过程变得轻松愉快。
进一步学习资源
- 官方文档:documentation/
- 示例代码:demo/src/sandboxes/
- GitHub仓库:https://gitcode.com/gh_mirrors/us/use-gesture
现在,你已经掌握了use-gesture的核心概念和使用方法,是时候将这些知识应用到你的项目中,为用户创造更加丰富和直观的交互体验了!
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



