React无动画拖拽功能实现:Mac OS下异常回退动画问题解决咨询
解决Mac OS上React拖拽卡片的回退动画问题
我正在复刻Trello的核心拖拽功能,目前功能已实现,但在MacBook上出现一个异常:将卡片从一列拖拽到另一列后,被拖拽的卡片会出现回到起始位置的动画效果,但实际上卡片的位置已经成功变更(Windows电脑无此问题)。我尝试使用Event.preventDefault()但没有解决问题。
以下是我的实现代码:
Column.js
import React, {useState, useRef} from 'react'; import './Column.css'; function Column({data}) { const [list, setList] = useState(data); const [dragging, setDragging] = useState(false); const dragItem = useRef(); const dragNode = useRef(); const handleDragStart = (event, params) => { console.log('drag starting', params) dragItem.current = params; dragNode.current = event.target; dragNode.current.addEventListener('dragend', handleDragEnd) setTimeout(() => { setDragging(true); }, 0) } const handleDragEnter = (event, params) => { console.log('entering drag', params); const currentItem = dragItem.current; if(event.target !== dragNode.current) { console.log('TARGET IS NOT THE SAME') setList(oldList => { let newList = JSON.parse(JSON.stringify(oldList)); newList[params.groupIndex].items.splice(params.itemIndex, 0, newList[currentItem.groupIndex].items.splice(currentItem.itemIndex,1)[0]) dragItem.current = params return newList; }) } } const handleDragEnd = () => { console.log('Ending Drag') setDragging(false); dragNode.current.removeEventListener('dragend', handleDragEnd) dragItem.current = null; dragNode.current = null; } const getStyles = (params) => { const currentItem = dragItem.current; if (currentItem.groupIndex === params.groupIndex && currentItem.itemIndex === params.itemIndex) { return 'current drag-and-drop-item'; } return 'drag-and-drop-item' }; return ( <section className="drag-and-drop-container"> <div className="drag-and-drop"> {list.map((group, groupIndex) => ( <div key={group.title} className="drag-and-drop-group" onDragEnter={dragging && !group.items.length ? (event) => handleDragEnter(event, {groupIndex, itemIndex:0}) : null } > <div className="drag-and-drop-group-title">{group.title}</div> {group.items.map((item, itemIndex) => ( <div draggable onDragStart={(dragEvent) => {handleDragStart(dragEvent, {groupIndex, itemIndex})}} onDragEnter={dragging ? (event) => {handleDragEnter(event, {groupIndex, itemIndex})} : null } key={item} className={dragging ? getStyles({groupIndex, itemIndex}) : "drag-and-drop-item" } > {item} </div> ))} </div> ))} </div> </section> ) } export default Column;
Column.css
@import url(./../../index.css); .drag-and-drop{ display: grid; gap: 0.5rem; width: 100%; height: 100%; grid-template-columns: repeat(auto-fill, 300px); background-color: var(--primary-color); padding: 0.5rem; align-items: start; } .drag-and-drop-group{ background-color: var(--secondary-color-80); padding: 0.5rem; } .drag-and-drop-group-title{ margin-bottom: 0.5rem; font-size: 1.2rem; font-family: 'Poppins'; } .drag-and-drop-item { background-color: #FFFFFF; color: var(--primary-color); min-height: 150px; } .drag-and-drop-item:not(:last-of-type){ margin-bottom: 0.5rem; } .current{ background-color: var(--primary-color); }
请问如何解决Mac OS上的这个异常动画问题?
解决方案
这个问题是Mac OS上WebKit内核的默认拖拽行为导致的——它会在拖拽结束时对原始元素播放一个"回弹"动画,即使你已经修改了DOM结构。以下是几个可以解决这个问题的方法:
1. 在dragstart事件中禁用默认行为并设置拖拽数据
Mac的WebKit对拖拽事件有特殊处理,如果你没有设置拖拽数据,它会使用默认的元素拖拽行为,从而产生回弹动画。在handleDragStart里添加这两行:
const handleDragStart = (event, params) => { console.log('drag starting', params) event.preventDefault(); // 先阻止默认行为 event.dataTransfer.setData('text/plain', ''); // 设置空拖拽数据,覆盖默认行为 // 其余原有代码... }
这能直接覆盖Mac的默认拖拽反馈,阻止回弹动画触发,改动最小且效果明显。
2. 优化拖拽时的原始元素隐藏逻辑
你的current类只是改变了背景色,但原始元素在拖拽时仍然留在DOM中,Mac的动画会作用于它。可以修改样式让拖拽中的原始元素完全隐藏:
.current { background-color: var(--primary-color); opacity: 0; /* 完全隐藏原始元素,避免动画被用户看到 */ pointer-events: none; /* 防止干扰其他拖拽事件 */ }
这样拖拽时用户看不到原始元素,自然也就察觉不到回弹动画了。
3. 补充dragleave事件处理
有时候Mac上dragEnter的触发时机有延迟,导致状态更新不及时。可以给拖拽分组容器添加onDragLeave事件,确保拖拽状态同步:
<div key={group.title} className="drag-and-drop-group" onDragEnter={dragging && !group.items.length ? (event) => handleDragEnter(event, {groupIndex, itemIndex:0}) : null } onDragLeave={(event) => event.preventDefault()} >
我建议先尝试第一种方法,如果还是有问题,再结合第二种方法隐藏原始元素,基本就能解决这个回弹动画的问题了。
内容的提问来源于stack exchange,提问作者Reeh
相关产品推荐
相关产品推荐

