Javascript 拖动';n';放下Div返回到新的最终位置

Javascript 拖动';n';放下Div返回到新的最终位置,javascript,html,css,reactjs,Javascript,Html,Css,Reactjs,我正在尝试创建一个拖放,在这里我可以将项目移动到列表上的不同位置,它将实时更新列表,因此,如果在下面的示例中,我将内容为1的div移动到内容为3的div,则div 2和3将向上移动,内容为1的div将位于第三个位置。到目前为止没有问题,我可以把它放在那里,一切都是正确的。 当我不放下并将div移动到一个不可放下的区域并让它离开时,问题就出现了,在这种情况下,它将返回到我第一次从第一个位置将其拖出的原始位置,但是,我希望它返回到3以前所在的新位置 示例代码: 开始拖动1: 将鼠标悬停在3上,是什

我正在尝试创建一个拖放,在这里我可以将项目移动到列表上的不同位置,它将实时更新列表,因此,如果在下面的示例中,我将内容为
1
的div移动到内容为
3
的div,则div 2和3将向上移动,内容为1的div将位于第三个位置。到目前为止没有问题,我可以把它放在那里,一切都是正确的。 当我不放下并将div移动到一个不可放下的区域并让它离开时,问题就出现了,在这种情况下,它将返回到我第一次从第一个位置将其拖出的原始位置,但是,我希望它返回到3以前所在的新位置

示例代码:

开始拖动1:

将鼠标悬停在3上,是什么让1取代了它

不停止拖动,向外移动并放下

我想让带有1的div返回到它在gree线后面的新位置,相反,它在红色线后面返回到它原来的位置

我的代码仅供参考

import React, { useState } from "react";
import "./App.css";

const initList = [1, 2, 3, 4, 5, 6, 7, 8, 9];
function App() {
  const [list, setList] = useState(initList);
  const [draggedItem, setDraggedItem] = useState(null);

  function onDragStartHandle(e, index) {
    setDraggedItem(list[index]);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/html", e.target.parentNode);
    e.dataTransfer.setDragImage(e.target.parentNode, 20, 22);
  }

  function onDragOverHandle(e, index) {
    e.preventDefault();

    const draggedOverItem = list[index];

    if (draggedOverItem === draggedItem) {
      return;
    }

    const items = list.filter((item) => item !== draggedItem);
    items.splice(index, 0, draggedItem);
    setList(items);
  }

  return (
    <div className="App">
      <header className="App-header">
        <h3>Drag'n'Drop</h3>
        <ul>
          {list.map((item, index) => (
            <li
              key={index}
              onDragOver={(e) => onDragOverHandle(e, index)}
              className="item-style"
            >
              <div draggable onDragStart={(e) => onDragStartHandle(e, index)}>
                {item}
              </div>
            </li>
          ))}
        </ul>
      </header>
    </div>
  );
}

export default App;
import React,{useState}来自“React”;
导入“/App.css”;
常量initList=[1,2,3,4,5,6,7,8,9];
函数App(){
const[list,setList]=useState(initList);
常量[draggedItem,setDraggedItem]=useState(null);
函数onDragStartHandle(e,索引){
setDraggedItem(列表[索引]);
e、 dataTransfer.effectAllowed=“移动”;
e、 dataTransfer.setData(“text/html”,例如target.parentNode);
e、 dataTransfer.setDragImage(e.target.parentNode,20,22);
}
函数onDragOverHandle(e,索引){
e、 预防默认值();
const draggedOverItem=列表[索引];
if(DRAGEDOVERITEM==DRAGEDITEM){
返回;
}
const items=list.filter((item)=>item!==draggedItem);
项目.拼接(索引,0,draggedItem);
设置列表(项目);
}
返回(
拖放
    {list.map((项目,索引)=>(
  • onDragOverHandle(e,索引)} className=“项目样式” > onDragStartHandle(e,索引)}> {item}
  • ))}
); } 导出默认应用程序;
好的,我花了一段时间才真正了解这一点,我能想到的最好办法是当你拖动一个元素并更新状态时,但是如果用户放弃拖放,该元素将“捕捉”回它的来源,而不是它悬停的最后一个位置。我花了一些时间研究了这个问题,但并没有什么能真正改变这种行为

我认为技术上更正确的行为是放弃拖放,即用户不在列表中拖放元素,是让列表保持它在拖动开始之前的状态

这里有一个解决方案,它添加了一个额外的状态片段,以便在拖动事件期间发生变化,如果拖放成功,则该临时状态将被提交到“真实”列表状态,如果不成功,则恢复到现有列表状态(只是保持不变)

import React,{useState}来自“React”;
导入“/App.css”;
常量initList=[1,2,3,4,5,6,7,8,9];
函数App(){
const[list,setList]=useState(initList);
const[dragList,setDragList]=useState(null);
常量[draggedItem,setDraggedItem]=useState(null);
/**
*拖动启动
*初始化要拖动的临时项并拖动列表。
*/
const onDragStartHandle=index=>e=>{
setDraggedItem(列表[索引]);
setDragList(列表);
e、 dataTransfer.effectAllowed=“移动”;
e、 dataTransfer.setData(“text/html”,例如target.parentNode);
e、 dataTransfer.setDragImage(e.target.parentNode,20,22);
};
/**
*在拖动端
*保存更新的拖动列表以列出临时值并使其为空。
*/
常量onDragEndHandle=e=>{
e、 预防默认值();
设置列表(dragList);
setDragList(空);
setDraggedItem(空);
};
/**
*左撇子
*项目未被删除,因此重置临时拖动列表
*/
const ondraglievehandle=e=>{
e、 预防默认值();
setDragList(列表);
};
/**
*拖过
*如果拖动到另一项上,请使用新位置更新拖动列表
*/
const ondragornandle=index=>e=>{
e、 预防默认值();
常数draggedOverItem=dragList[index];
if(DRAGEDOVERITEM==DRAGEDITEM){
返回;
}
const items=dragList.filter(item=>item!==draggedItem);
项目.拼接(索引,0,draggedItem);
setDragList(项目);
};
返回(
拖放
    {(draggedItem?dragList:list).map((项,索引)=>(
  • {item}
  • ))}
); } 导出默认应用程序;
*
li
元素移动到
div
,以保留来自同一元素的所有事件。将
onDragOver
事件侦听器放在列表项上会导致一个奇怪的问题,有时UI会“卡住”在半悬停状态


好的,我花了一段时间才真正了解这一点,我能想到的最好办法是当你拖动一个元素并更新状态时,但是如果用户放弃拖放,该元素将“捕捉”回它原来的位置,而不是它悬停的最后一个位置。我花了一些时间研究了这个问题,但并没有什么能真正改变这种行为

我认为技术上更正确的行为是放弃拖放,即用户不在列表中拖放元素,是让列表保持它在拖动开始之前的状态

这里有一个解决方案,它添加了一个额外的状态片段,以便在拖动过程中进行变异
import React, { useState } from "react";
import "./App.css";

const initList = [1, 2, 3, 4, 5, 6, 7, 8, 9];

function App() {
  const [list, setList] = useState(initList);
  const [dragList, setDragList] = useState(null);
  const [draggedItem, setDraggedItem] = useState(null);

  /**
   * On drag start
   * Initialize the temporary item being dragged and drag list.
   */
  const onDragStartHandle = index => e => {
    setDraggedItem(list[index]);
    setDragList(list);
    e.dataTransfer.effectAllowed = "move";
    e.dataTransfer.setData("text/html", e.target.parentNode);
    e.dataTransfer.setDragImage(e.target.parentNode, 20, 22);
  };

  /**
   * On drag end
   * Save updated drag list to list and nullify temporary values.
   */
  const onDragEndHandle = e => {
    e.preventDefault();
    setList(dragList);
    setDragList(null);
    setDraggedItem(null);
  };

  /**
   * On drag leave
   * Item wasn't dropped so reset temporary drag list
   */
  const onDragLeaveHandle = e => {
    e.preventDefault();
    setDragList(list);
  };

  /**
   * On drag over
   * If dragging over another item update the drag list with new position
   */
  const onDragOverHandle = index => e => {
    e.preventDefault();

    const draggedOverItem = dragList[index];

    if (draggedOverItem === draggedItem) {
      return;
    }

    const items = dragList.filter(item => item !== draggedItem);
    items.splice(index, 0, draggedItem);
    setDragList(items);
  };

  return (
    <div className="App">
      <header className="App-header">
        <h3>Drag'n'Drop</h3>
        <ul>
          {(draggedItem ? dragList : list).map((item, index) => (
            <li key={index} className="item-style">
              <div
                draggable
                onDragOver={onDragOverHandle(index)} // Moved *
                onDragLeave={onDragLeaveHandle}
                onDragEnd={onDragEndHandle}
                onDragStart={onDragStartHandle(index)}
              >
                {item}
              </div>
            </li>
          ))}
        </ul>
      </header>
    </div>
  );
}

export default App;