HTML 및 React를 사용하여 드래그 앤 드롭 재정렬

6115 단어 reacthtmljavascript
요즘 자바스크립트로 작업하면서 항목 목록을 렌더링하려는 시나리오에 자주 직면하게 됩니다. 하지만 사용자가 해당 항목을 즉석에서 다시 주문할 수 있도록 하려면 어떻게 해야 할까요? 여기에서는 React와 함께 HTML5의 드래그 앤 드롭(DnD) API를 사용하여 사용자가 원하는 내용을 쉽게 이동할 수 있도록 하는 방법을 보여드리겠습니다.

먼저 렌더링할 항목 목록이 필요합니다!



화면에 3개의 다채로운 상자를 렌더링하는 간단한 React 앱부터 시작하겠습니다.



App.js

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

const App = () => {
  const [boxes, setBoxes] = useState([
    {
      id: "Box-1",
      color: "red",
      order: 1
    },
    {
      id: "Box-2",
      color: "green",
      order: 2
    },
    {
      id: "Box-3",
      color: "blue",
      order: 3
    }
  ]);

  return (
    <div className="App">
      {boxes
        .sort((a, b) => a.order - b.order)
        .map((box) => (
          <Box
            key={box.id}
            boxColor={box.color}
            boxNumber={box.id}
          />
        ))}
    </div>
  );
}

export default App;


Box.js

import React from "react";

const Box = ({ boxColor, boxNumber }) => {
  return (
    <div
      id={boxNumber}
      style={{
        backgroundColor: boxColor,
        border: "1px solid",
        borderColor: boxColor,
        borderRadius: "5px",
        color: "#FFF",
        width: "30%",
        height: "100px"
      }}
    >
      {boxNumber}
    </div>
  );
};

export default Box;



그러면 위의 그림과 같은 상자가 렌더링됩니다. 그러나 그들은 아직 아무것도 하지 않습니다!

Note the way the boxes are sorted to be rendered based on the order attribute in their objects



다음 단계는 DnD API를 상자에 도입하는 것입니다.



이를 위해 Box.js로 돌아가서 <div> 에 몇 가지 속성을 추가합니다. 다음과 같이 변경하겠습니다.

const Box = ({ boxColor, boxNumber, handleDrag, handleDrop }) => {
  return (
    <div
      draggable={true}
      id={boxNumber}
      onDragOver={(ev) => ev.preventDefault()}
      onDragStart={handleDrag}
      onDrop={handleDrop}
      style={{
        backgroundColor: boxColor,
        border: "1px solid",
        borderColor: boxColor,
        borderRadius: "5px",
        color: "#FFF",
        width: "30%",
        height: "100px"
      }}
    >
      {boxNumber}
    </div>
  );
};



가장 먼저 주목해야 할 것은 이제 handleDraghandleDrop 두 개의 추가 소품을 가져오고 있다는 것입니다. 이것들은 각각 상자를 드래그 앤 드롭할 때 발생하는 일을 처리하기 위해 App.js에서 전달할 함수일 뿐입니다.

또한 <div> 에 몇 가지 속성을 추가했습니다.
이러한 각 속성이 수행하는 작업에 대해 너무 자세히 설명하지는 않겠지만 간략하게는 다음과 같습니다.
  • draggable 요소를 드래그할 수 있는지 여부를 설정합니다.
  • onDragStart는 요소 드래그를 시작할 때 트리거되는 이벤트 리스너입니다.
  • onDrop는 요소를 놓을 때 트리거되는 이벤트 리스너입니다.
  • onDragOver는 요소를 다른 항목 위로 드래그할 때 트리거되는 이벤트 리스너입니다.

  • 방금 전달한 onDragStart prop에 handleDrag를 설정하고 onDrop prop에 handleDrop를 설정합니다.
    onDragOver의 경우 브라우저의 기본 작업을 방지하는 기능을 설정할 것입니다. 일반적으로 링크 또는 이와 유사한 항목으로 이동하려고 시도합니다.

    이제 App.js를 위해.



    여기서 handleDraghandleDrop 함수를 추가한 다음 Box 구성 요소로 전달합니다.

    따라서 handleDrag부터 시작하여 한 번에 하나씩 가져옵니다.

      const [dragId, setDragId] = useState();
    
      const handleDrag = (ev) => {
        setDragId(ev.currentTarget.id);
      };
    


    현재 드래그하고 있는 상자를 추적하기 위해 dragId라는 새 상태 변수를 추가했습니다. handleDrag 함수 자체 내에서 우리가 하는 일은 이벤트에서 상자 ID를 가져와 상태로 설정하는 것뿐입니다.
    handleDrop는 두 함수 중 더 복잡하며 여기에서 모든 '전환' 코드를 처리합니다.

      const handleDrop = (ev) => {
        const dragBox = boxes.find((box) => box.id === dragId);
        const dropBox = boxes.find((box) => box.id === ev.currentTarget.id);
    
        const dragBoxOrder = dragBox.order;
        const dropBoxOrder = dropBox.order;
    
        const newBoxState = boxes.map((box) => {
          if (box.id === dragId) {
            box.order = dropBoxOrder;
          }
          if (box.id === ev.currentTarget.id) {
            box.order = dragBoxOrder;
          }
          return box;
        });
    
        setBoxes(newBoxState);
      };
    


    여기에서 먼저 어떤 상자가 드래그되고 있고 어떤 상자에 놓였는지 식별하려고 합니다. 배열find() 메서드를 사용하여 각 상자 ID를 드래그 중인 상자에 대한 dragId(handleDrag에서 설정한)와 비교하고 상자를 드롭하는 이벤트를 방출하는 요소의 ID와 비교합니다. 에.

    상자의 순서를 변경할 것이기 때문에 두 상자의 원래 순서가 변경되는 것을 원하지 않으므로 dragBoxOrderdropBoxOrder 변수에서 이를 기록해 둘 것입니다.

    마지막으로 실제 스위치로 이동합니다.

        const newBoxState = boxes.map((box) => {
          if (box.id === dragId) {
            box.order = dropBoxOrder;
          }
          if (box.id === ev.currentTarget.id) {
            box.order = dragBoxOrder;
          }
          return box;
        });
    


    배열map() 함수를 사용하여 상자 순서를 재정렬하고 새 배열로 반환할 수 있습니다. map() 함수 내에서 현재 상자의 id가 dragId와 같은지 확인합니다. 그렇다면 주문을 dropBoxOrder로 설정합니다. 그렇지 않은 경우 드롭되는 상자의 ID와 같은지 확인하고 true인 경우 해당 순서를 dragBoxOrder로 설정합니다.

    따라서 map() 함수 실행이 중지되면 관련된 두 상자의 order 변수가 교체된 newBoxState 변수에 새 배열이 있어야 합니다. 그런 다음 상자 객체의 이 새로운 배열을 상태로 설정하고 다시 렌더링을 트리거할 수 있습니다.

    전체 코드를 보거나 완성된 데모를 재생하려면 이 코드 샌드박스를 확인하십시오.
    https://codesandbox.io/s/react-drag-drop-reorder-mxt4t?fontsize=14&hidenavigation=1&theme=dark

    좋은 웹페이지 즐겨찾기