使用@react-spring/web实现Div位置交换动画遇Bug求助
问题分析与解决方案
你的交换动画无法完整生效,核心问题出在状态更新时机错误、初始弹簧配置不完整以及布局定位缺失这三个点上:
问题根源
- 状态提前覆盖:触发动画后立刻更新
coord状态,导致后续动画的基准位置被提前修改,动画还未完成就使用新状态作为起始,直接中断了过渡过程。 - 弹簧配置错误:初始化
useSprings时仅设置了from(过渡起点),未设置to(持久目标状态),组件挂载后无法维持正确的初始位置。 - 布局未脱离文档流:
animated.div默认是块级元素,translate移动后会保留原文档流占位,视觉上无法实现真正的位置交换。
修正后的代码
import { useState } from 'react'; import { useSprings, animated } from '@react-spring/web'; const initialCoords = [ { x: 0, y: 0 }, { x: 200, y: 0 } ]; export default function SwapAnimation() { const [coord, setCoord] = useState(initialCoords); // 初始化弹簧,直接绑定当前coord的x/y作为持久状态 const [springs, api] = useSprings(2, (i) => ({ x: coord[i].x, y: coord[i].y, config: { tension: 200, friction: 20 } })); const swapBoxes = async () => { const targetCoords = [coord[1], coord[0]]; // 启动动画,从当前位置过渡到目标位置 await api.start((i) => ({ to: { x: targetCoords[i].x, y: targetCoords[i].y } })); // 动画完成后再更新状态,避免干扰动画过程 setCoord(targetCoords); }; return ( <div style={{ position: 'relative', minHeight: '100px' }}> <animated.div style={{ ...springs[0], position: 'absolute' }}> <div style={{ border: '1px solid red', width: '100px', height: '100px' }}> A </div> </animated.div> <animated.div style={{ ...springs[1], position: 'absolute' }}> <div style={{ border: '1px solid red', width: '100px', height: '100px' }}> B </div> </animated.div> <button onClick={swapBoxes}>交换位置</button> </div> ); }
关键修改说明
- 布局定位:父容器设置
position: relative,子元素animated.div设置position: absolute,让元素脱离文档流,确保移动时不会保留占位。 - 动画与状态同步:使用
await等待动画完成后再更新coord状态,避免状态提前修改导致动画异常。 - 弹簧配置优化:初始化时直接绑定
x/y为当前状态值,替代仅设置from,确保组件挂载后元素处于正确初始位置。
内容的提问来源于stack exchange,提问作者Fear4Haunt
相关产品推荐
相关产品推荐

