본문 바로가기
이미지 미리보기프로젝트

이미지 미리보기 & 삭제 & 순서 바꾸 바꾸기

1분프로젝트티스토리에서 옮긴 글

tsx
  const [dragStartIndex, setDragStartIndex] = useState<null | number>(null);
  const [dragEnterIndex, setDragEnterIndex] = useState<null | number>(null);


  const handleAddShowImg = (e: ChangeEvent<HTMLInputElement>) => {
    if (!e.target.files) return;
    if (e.target.files.length + showImg.length > 8) {
      alert('등록할 수 있는 이미지의 최대 갯수는 8장입니다.');
      return;
    }

    const imgList = e.target.files;
    const imgUrlList = [...showImg];

    for (let i = 0; i < imgList.length; i++) {
      const imgSrc = URL.createObjectURL(imgList[i]);
      const imgName = imgList[i].name;
      imgUrlList.push({ imgSrc, imgName });
    }

    setShowImg(imgUrlList);
  };

  const handleDeleteShowImg = (index: number) => {
    const newShowImgs = showImg.filter((img, i) => i !== index);
    setShowImg(newShowImgs);
  };

  const handleDrag = () => {
    if (dragStartIndex === null || dragEnterIndex === null) return;

    const newShowImgs = [...showImg];
    const spliceImg = newShowImgs.splice(dragStartIndex, 1)[0];

    newShowImgs.splice(dragEnterIndex, 0, spliceImg);
    setShowImg(newShowImgs);
  };

<tr>
              <td className='text-sm font-medium border bg-gray-200 border-gray-300 text-center'>
                Photo
              </td>
              <td className='border border-gray-300 p-2'>
                <div className='flex flex-col gap-1 w-full'>
                  <label
                    htmlFor='photo'
                    className='w-20 border border-gray-400 text-gray-700 hover:bg-gray-50 rounded-md flex justify-center items-center py-0.5 cursor-pointer'
                  >
                    파일 선택
                    <input
                      id='photo'
                      type='file'
                      accept='image/png, image/jpeg'
                      multiple
                      onChange={(e) => handleAddShowImg(e)}
                      className='hidden'
                    />
                  </label>
                  {showImg.length > 0 && (
                    <div className='flex w-full gap-1 py-2 flex-wrap'>
                      {showImg.map((img, i) => {
                        return (
                          <div key={`${img.imgName} + ${i}`}>
                            <img
                              className='w-32 h-32 border border-gray-300 cursor-move'
                              src={img.imgSrc}
                              alt={`${img.imgName} + ${i}`}
                              onDragStart={() => setDragStartIndex(i)}
                              onDragEnter={() => setDragEnterIndex(i)}
                              onDragEnd={() => handleDrag()}
                            />
                            <div className='flex items-center justify-between mt-1'>
                              <span className='truncate max-w-[5rem] text-'>
                                {img.imgName}
                              </span>
                              <button
                                className='border px-1 rounded-md'
                                onClick={() => handleDeleteShowImg(i)}
                              >
                                삭제
                              </button>
                            </div>
                          </div>
                        );
                      })}
                    </div>
                  )}
                  <span className='text-xs text-red-600'>
                    ※ 등록한 사진 순서대로 게시글에 보여집니다.
                  </span>
                  <span className='text-xs text-red-600'>
                    ※ 한 게시물당 최대 5개의 사진을 등록할 수 있습니다.
                  </span>
                </div>
              </td>
</tr>

핵심은 이미지마다 onDragStart, onDragEnter Event를 통해서 작업을 했습니다.

onDragStart는 마우스로 집은 이미지의 Index를 dragStartIndex state로 관리하였고 집은 이미지가 Enter 즉 올라갔을 때 onDragEnter Event를 통해서 dragEnterIndex state를 관리하였습니다.

splice() 함수를 통해서 이미지의 순서를 바꾸는 로직은 onDragEnd Event를 통해서 호출했는데 onDragEnd Event가 호출되면 이미지 이동이 끝났기 때문에 이때 함수를 실행시켰습니다.

실행 화면
그림 1. 실행 화면
  • #ondragend
  • #onDragEnter
  • #ondragstart
  • #이미지 미리보기
  • #이미지 삭제
  • #이미지 순서바꾸기

프로젝트의 다른 글