SuperAPI AI 工具集

framer-motion-gestures

前端与建站

查看项目

更新于 10-15 16:27

技能介绍

Framer Motion 手势技能用于实现手势驱动的动画:拖拽、平移、点按、悬停、聚焦或触摸交互。当用户询问拖拽、交互元素或 Framer Motion 中基于手势的 UI 时适用。相关技能:核心动画使用 framer-motion-core;变体使用 framer-motion-variants;布局动画使用 framer-motion-layout。

拖拽(Drag) 通过 drag 属性启用拖拽:

<motion.div drag="x" dragConstraints={{ left: -100, right: 100 }} whileDrag={{ scale: 1.1, cursor: "grabbing" }} />

拖拽属性

属性 类型 描述
drag bool | "x" | "y" 在指定轴上启用拖拽
dragConstraints object | RefObject 移动约束
dragMomentum boolean 释放后继续惯性(默认:true)
dragElastic number | object 边界的弹性(默认:0)
dragTransition Transition 惯性的弹簧配置
whileDrag MotionProps 拖拽过程中的动画
onDrag function 拖拽过程中的回调
onDragStart function 拖拽开始时的回调
onDragEnd function 拖拽结束时的回调

拖拽约束

<motion.div drag dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }} />

基于 ref 的约束

function Draggable() { const constraintsRef = useRef(null);

return ( <> <motion.div ref={constraintsRef} style={{ width: 500, height: 500, backgroundColor: "#eee" }} /> <motion.div drag dragConstraints={constraintsRef} /> </> ); }

平移(Pan) 平移与拖拽类似,但用于指针/触摸:

<motion.div drag="x" onDrag={(e, info) => { console.log("Position:", info.point); console.log("Velocity:", info.velocity); }} />

平移与拖拽的区别

  • 拖拽:带视觉反馈、惯性和约束的鼠标/触摸交互
  • 平移:更低层级的指针跟踪,无惯性

点按(whileTap) 按下时的动画:

<motion.button whileTap={{ scale: 0.95, opacity: 0.8 }} whileHover={{ scale: 1.05 }}

Click me </motion.button>

悬停(whileHover) 悬停时的动画:

<motion.div whileHover={{ scale: 1.1, backgroundColor: "#ff0000" }} style={{ width: 100, height: 100, backgroundColor: "#00ff00" }} />

onHoverStart / onHoverEnd

<motion.div onHoverStart={() => console.log("Hover started")} onHoverEnd={() => console.log("Hover ended")} />

聚焦(whileFocus) 聚焦时的动画(键盘):

<motion.input whileFocus={{ scale: 1.05, borderColor: "#00ff00" }} style={{ borderWidth: 2 }} />

带弹簧物理的拖拽

<motion.div drag="x" dragConstraints={{ left: -200, right: 200 }} dragTransition={{ type: "spring", stiffness: 300, damping: 20, mass: 1 }} />

带约束的拖拽控制

function DraggableBox() { const constraintsRef = useRef(null);

return ( <> <motion.div ref={constraintsRef} style={{ width: 500, height: 500, backgroundColor: "#f0f0f0" }} /> {[1, 2, 3].map(i => ( <motion.div key={i} drag dragConstraints={constraintsRef} dragMomentum={false} whileDrag={{ scale: 1.1 }} /> ))} </> ); }

滑动检测

function Swipeable() { const x = useMotionValue(0); const { scrollYProgress } = useScroll();

const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);

return ( <motion.div style={{ x, opacity }} drag="x" dragConstraints={{ left: 0, right: 0 }} dragElastic={1} /> ); }

手势状态信息 回调接收 PointInfo 和 DragInfo:

onDrag={(e, info) => { info.point // { x, y } 位置 info.velocity // { x, y } 速度 info.offset // { x, y } 相对起点的偏移 }}

最佳实践

  • 使用 dragConstraints 使元素保持在边界内。
  • 使用 dragElastic 实现回弹效果。
  • 使用 whileDrag 在拖拽过程中提供视觉反馈。
  • 使用 dragMomentum 实现自然的延续。
  • 使用带 spring 的 dragTransition 实现基于物理的拖拽。
  • 在容器内拖拽时,使用 ref 作为约束。

避免

  • 若元素应保持在边界内,不要在没有 dragConstraints 的情况下使用 drag。
  • 不要忘记拖拽事件只有在指针移动超过阈值后才会触发。
  • 不要使用过大的 dragElastic,可能导致视觉故障。
  • 不要在拖拽期间动画化冲突属性(例如 scale 与 x)。

了解更多 https://www.framer.com/motion/gestures/ https://www.framer.com/motion/drag/