상세 컨텐츠

본문 제목

Drag & Drop 적용과 활용하는 법~

유데미 스나이퍼팩토리

by penloo 2024. 7. 21. 21:57

본문

" 선배 드래그해주세요~ 드롭도 같이? "

 

 

 

피그마로 와이어 프레임 만든것



자 오늘 필자는 저 카드를 드래그하여 빈곳에 드롭하여 적용시키는 일을 저지를거다 



이곳에 많은 기능을 모아두었으니 참고하면 좋을 거 같다!

https://inpa.tistory.com/entry/드래그-앤-드롭-Drag-Drop-기능#

 

🌐 드래그 앤 드롭(Drag and Drop) 기능 이해 & 구현하기

HTML 드래그 앤 드롭 사용법 드래그(drag)와 드롭(drop)은 컴퓨터를 이용하면서 정말 많이 사용하는 기능 중에 하나일 것이다. 파일 애플리케이션에서 문서를 복사해 이동하는 것 부터 주문 하려는

inpa.tistory.com

 

페이지 안에 먼저 다 구현하고 나중에 컴포넌트를 따로 만들 예정이다, 먼저 초기 구성된 사진을 보면

 

 

 

이렇게  <PlayerCard> 컴포넌트는 만들어진 상태이고  선수 정보 값을 map으로 가져오는 형태로 

  {startingMember.map((player, index) => (
              <div
                style={{
                  transform: "scale(1)",
                }}
                onClick={handlePlayerCardClick(player.pcode)}
                key={index}
                className={`absolute cursor-pointer ${getPositionStyle(
                  player.position_translated || player.position
                )}`}
              >
                <PlayerCard
                  name={player.name}
                  imageUrl={player.imageUrl}
                  num={player.num}
                  position_translated={
                    player.position_translated || player.position
                  }
                  rating={player.rating}
                  pcode={player.pcode}
                  changeinn={player.changeinn}
                />
              </div>
            ))}

 갖춰놓은 형태도 마지막엔 여기서 몇가지 요소를 추가하니 잘 관찰하도록 하자!

 

 

 

먼저 와이어프레임에서 만든 빈칸 Image를 똭! 가져온다 

   <Image
          onDrop={handleDrop}
          onDragOver={handleDragEnter}
          src="/images/drag.svg"
          alt="빈 칸"
          width={150}
          height={190}
        />

 

 

그리고 드롭할 선수의 droppedPlayer 상태를 추가하여 드래그 앤 드롭된 PlayerCard 정보를 저장한다 (아직 문제 있음)

 

const [droppedPlayer, setDroppedPlayer] = useState(null);

 

 

handleDragStart 함수: 드래그가 시작될 때 player 정보를 데이터 전송 객체에 저장한다 (트러블 슈팅-> (player)이름을 못찾는다)

  const handleDragStart = (event: React.DragEvent<HTMLImageElement>) => {
    event.dataTransfer.setData("player", JSON.stringify(player));
  };

 

handleDrop 함수: 드롭된 데이터를 droppedPlayer 상태로 설정하여 이미지를 대체한다

 const handleDrop = (event: React.DragEvent<HTMLDivElement>) => {
    event.preventDefault();
    const data = event.dataTransfer.getData("player");
    if (data) {
      setDroppedPlayer(JSON.parse(data));
    }
  };

 

조건부 렌더링: droppedPlayer 상태가 null일 경우 Image 컴포넌트를, 그렇지 않을 경우 PlayerCard 컴포넌트를 렌더링하게 조건을 만든다

 

  <div
        onDrop={handleDrop}
        onDragOver={handleDragEnter}
        style={{ width: 150, height: 190, border: "1px dashed gray" }}
      >
        {droppedPlayer ? (
          <PlayerCard
            name={droppedPlayer.name}
            imageUrl={droppedPlayer.imageUrl}
            num={droppedPlayer.num}
            position_translated={droppedPlayer.position_translated || droppedPlayer.position}
            rating={droppedPlayer.rating}
            pcode={droppedPlayer.pcode}
            changeinn={droppedPlayer.changeinn}
          />
        ) : (
          <Image
            src="/images/drag.svg"
            alt="빈 칸"
            width={150}
            height={190}
          />
        )}
      </div>

 

 

 

 요롷게 해주면 참 보기 싫은 빨간줄 파티가 이뤄진다 이유가 뭘까?

바로 나는 next.js와 typescript를 쓰기 때문이다 그래서 타입을 지정해줘야하는데 일단은 빨리 넘어가기 위해 

any를 집어넣어주겠다.

 

그러면 아까 있던  " 드롭할 선수의 droppedPlayer 상태를 추가하여 드래그 앤 드롭된 PlayerCard 정보를 저장한다 (문제 해결)" 가 완료

  const [droppedPlayer, setDroppedPlayer] = useState<any>(null);

 

그리고 이번에는 두번째 트러블

"handleDragStart 함수: 드래그가 시작될 때 player 정보를 데이터 전송 객체에 저장한다 (트러블 슈팅-> (player)이름을 못찾는다)"

 

먼저 이 함수를 쓰기위하여

onDragStart={handleDragStart(player)}
draggable

를 

PlayerCard 컴포넌트들을 드래그 가능하도록 draggable 속성을 추가하고 ,
handleDragStart 함수에 드래그 시작 시 (player) 데이터를 dataTransfer 객체에 저장합니다 json형식으로
그리고, 역시나 typescript 죠?

 

 const handleDragStart =
    (player: any) => (event: React.DragEvent<HTMLDivElement>) => {
      event.dataTransfer.setData("player", JSON.stringify(player));
    };

 

이런식으로 마무리해주면 된다!

이후 컴포넌트화하여 완료해주었다 

 

하지만 저 영상과 같이 교체는 되지만, 다시 빈칸으로 삭제가 되지 않는 문제점이 있다

 

그래서 추가로 삭제하는 함수를 만들어주었다.

  const handleRemovePlayer = (event: React.MouseEvent<HTMLButtonElement>) => {
    event.stopPropagation();// 전파막기 
    setDroppedPlayer(null);
  };  //삭제기능 함수

 

??

stopPropagation() 왜 필요한가?

handleRemovePlayer 함수 내부에서 event.stopPropagation()을 사용하지 않으면,

삭제 버튼을 클릭했을 때 클릭 이벤트가 부모 요소로 전달될 수 있다.

이것은 의도하지 않은 부작용을 일으킬 수 있으며, 예를 들어 부모 요소가 클릭 이벤트를 처리하는 다른 핸들러를 가지고 있을 때 문제가 될 수 있다.

 

이후

return값에 추가하여 삭제까지 완료가 되었다 ~!

 

관련글 더보기