React列表拖拽项动画优化技术求助
优化React拖拽列表的顺滑动画效果
问题背景
已实现包含10个项的React拖拽排序列表,基础抓取动画已完成,但拖拽过程中列表项移动卡顿,希望实现:
- 拖拽项顺滑上下移动
- 被拖拽覆盖的项向相反方向顺滑移动
- 避免项重叠导致的事件触发错误
优化后可运行代码
JavaScript 部分
const App = () => { const [myArray, setMyArray] = React.useState([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); const [draggedIndex, setDraggedIndex] = React.useState(-1); const [dragDirection, setDragDirection] = React.useState(null); // 记录拖拽方向:up/down const onDragStart = (e, index) => { setDraggedIndex(index); const emptyDiv = document.createElement('div'); emptyDiv.style.width = '0px'; emptyDiv.style.height = '0px'; e.dataTransfer.setDragImage(emptyDiv, 0, 0); }; const onDragOver = (e, index) => { e.preventDefault(); if (draggedIndex === -1 || draggedIndex === index) return; // 判断拖拽方向 const direction = index < draggedIndex ? 'up' : 'down'; setDragDirection(direction); // 更新数组顺序 const newArray = [...myArray]; const [draggedItem] = newArray.splice(draggedIndex, 1); newArray.splice(index, 0, draggedItem); setMyArray(newArray); setDraggedIndex(index); }; const onDragEnd = (e) => { setDraggedIndex(-1); setDragDirection(null); }; return ( <div className="App"> {myArray.map((x, i) => { let itemClass = 'listItem'; // 给拖拽项添加方向类,给被移动的项添加反向类 if (i === draggedIndex) { itemClass += ` draggable dragged-${dragDirection}`; } else if (dragDirection === 'up' && i === draggedIndex + 1) { itemClass += ' listItem-down'; } else if (dragDirection === 'down' && i === draggedIndex - 1) { itemClass += ' listItem-up'; } return ( <div className={itemClass} draggable key={x} onDragStart={(e) => onDragStart(e, i)} onDragOver={(e) => onDragOver(e, i)} onDragEnd={onDragEnd} > <h3>hello - {x}</h3> </div> ); })} </div> ); } ReactDOM.render(<App />, document.getElementById('root'));
CSS 部分
.App { text-align: center; align-items: center; display: flex; flex-direction: column; gap: 5px; /* 用gap替代margin,避免margin重叠问题 */ } .listItem { border: 2px solid black; width: 400px; padding: 10px; cursor: grab; transition: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1); position: relative; z-index: 1; } .draggable { border-color: green; transform: scale(1.08); cursor: grabbing; z-index: 10; /* 拖拽项置于顶层,避免被其他项遮挡 */ } /* 拖拽项向上移动的动画 */ .dragged-up { transform: scale(1.08) translateY(-100%); } /* 拖拽项向下移动的动画 */ .dragged-down { transform: scale(1.08) translateY(100%); } /* 其他项向下移动的动画 */ .listItem-down { transform: translateY(100%); z-index: 0; } /* 其他项向上移动的动画 */ .listItem-up { transform: translateY(-100%); z-index: 0; }
HTML 部分
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script> <div id="root"></div>
关键改动说明
- 状态管理:新增
dragDirection状态记录拖拽方向(up/down),用于给对应项添加动画类 - 项类名动态控制:根据当前索引和拖拽方向,给拖拽项和被移动的相邻项添加对应的动画类
- CSS优化:
- 用
gap替代margin避免项间距重叠问题 - 给拖拽项设置更高的
z-index,确保其在顶层,防止事件被遮挡 - 使用
cubic-bezier过渡曲线让动画更自然 - 为不同方向的移动定义对应的
translateY变换,实现顺滑的位置过渡
- 用
- 数组更新逻辑:改用
slice和splice的组合,更清晰地处理拖拽项的位置调整
内容的提问来源于stack exchange,提问作者Sebastian Meckovski
相关产品推荐
相关产品推荐

