关于 r3f-interaction
面向 React Three Fiber 开发者的交互技能,提供指针、拖拽、相机和键盘输入的实现指导。重点说明事件语义、输入所有权与边界情况的验证。
主要功能
- 01R3F 指针事件语义
- 02对象拖拽与控制器协调
- 03键盘和连续输入处理
- 04触屏、捕获与取消处理
- 05交互边界情况测试
适用场景
- 01实现可选择的 3D 对象
- 02避免拖拽与相机控制冲突
- 03处理触屏及画布外拖动
- 04验证键盘输入和焦点行为
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ enzed/ r3f-skills --skill r3f-interaction安装后在 Claude Code 中输入/r3f-interaction确认已加载。
详细介绍
React Three Fiber 交互
先检查已安装的 Fiber、Drei 和输入库版本。示例针对 Fiber 9 / React 19。连接处理程序之前,先确定由谁负责相机移动、对象移动和 UI 输入。
可选对象
在 Canvas 下挂载。重要操作应在 Canvas 外保留可访问的 DOM 控件;仅靠网格指针处理程序无法提供键盘访问。
import { useState } from 'react'
import { OrbitControls } from '@react-three/drei'
export default function Example() {
const [selected, setSelected] = useState(false)
return (
<>
<mesh
name="selectable-box"
onClick={(event) => {
event.stopPropagation()
setSelected((value) => !value)
}}
>
<boxGeometry />
<meshStandardMaterial color={selected ? 'gold' : 'coral'} />
</mesh>
<OrbitControls makeDefault />
</>
)
}
事件语义
- R3F 会对带有处理程序的对象进行射线检测,并按距离顺序分发命中事件,然后沿祖先链冒泡。
event.object是命中的对象;event.eventObject是拥有处理程序的对象。 stopPropagation()会阻止事件分发到更远处的命中对象以及祖先对象。它会改变事件分发,不会跳过已经执行的射线检测。调用它可能会立即在此前位于命中对象后方的悬停对象上触发 pointerout。event.point使用世界坐标。保留值时请先克隆,并在赋给局部变换之前转换到父级的局部空间。要将 2D 拖动映射到 3D,需要平面交点或深度参考。- 使用 Canvas 的
onPointerMissed处理背景取消选择;根据事件的移动信息和应用的手势策略区分点击与拖动。 - 在 R3F 中,指针捕获是对命中测试的补充。通过
event.target.setPointerCapture(event.pointerId)和对应的释放方法进行捕获和释放;还要处理取消和捕获丢失的情况。 - 指针静止时相机移动,可能需要调用
state.events.update()刷新悬停结果。仅在必要时调用,不要每帧都额外进行一次射线检测。 - 对于开销较大的拾取操作,请使用更简单的命中代理或图层过滤。不要仅依靠视觉透明度来阻止相交。
控件与拖动的责任归属
- 使用 OrbitControls 进行环绕;需要脚本化过渡和更丰富的相机行为时,使用 CameraControls。复制属性或方法之前,请检查已安装的 Drei / 底层控件版本。
- Drei 控件会管理帧更新和按需失效。在同一相机上挂载多个活动控件时,除非已明确协调,否则应避免这样做。
makeDefault会向与控件协调的辅助工具提供控件实例。拖动时,TransformControls 可以暂停默认控件;请确认自定义控件也能正确禁用和恢复。- 对象拖动时,应根据所需约束选择 Drei DragControls/PivotControls/TransformControls。区分受控矩阵与自动变换;不要同时对同一对象应用两者。
- 自定义拖动时,保存初始变换、捕获指针、投影到选定平面,并在 pointerup、取消和卸载时恢复相机控件。请在实际事件目标上遵循 touch-action 要求。
- 共享的 DOM 事件源需要与事件目标和画布矩形一致的坐标前缀。请测试滚动和叠加层;盲目选择
client坐标可能造成偏移。
键盘与连续输入
- Drei KeyboardControls 提供命名操作。移动时,在
useFrame内读取其 getter;仅在离散事件中订阅,并清理订阅。 - 如果需要保持恒定速度,请对对角移动进行归一化;视觉移动需乘以 delta。对于物理刚体,应将输入传递给物理步进逻辑,而不是直接移动其网格。
- 焦点丢失时清除按住状态,并注意文本字段的焦点。指针锁定、全屏和音频可能需要明确的用户手势。
- 高频指针位置使用 refs,语义事件使用 React state。不要仅为节流一个处理程序而添加 lodash 或状态库;确有节流需要时,请清理计时器。
- ScrollControls 会创建滚动上下文;
useScroll应放在其下方。其归一化的 offset/delta 不是像素距离。
验证
测试重叠网格、嵌套组、点击背景取消选择、拖动到画布外、触控、取消操作、焦点丢失以及键盘替代操作。验证拖动后相机控件能否恢复正常。
来源
评论
支持 Markdown