구현하기 전에 왜 그렇게 겁냈을까.. 몇 줄만 추가하면 되는 것을!

드래그 앤 드랍 구현하기


① 이미지 업로드하기 #1 - VueJS + NodeJS

② 이미지 업로드하기 #2 - Amazon S3 setting + upload

이미지 업로드하기 #3 - Drag and Drop

④ 이미지 업로드하기 #4 - Multi image management

 

 

 이전 이미지 업로드하기 #1 에서는 클릭을 통해 이미지 업로드를 했다면 이번에는 드래그 앤 드랍을 통해 이미지 업로드하는 방법에 대해 포스팅하겠습니다.

끌어서 놓기

  ▶ FRONTEND

src/views/upload.vue

<template>
<div class="container mx-auto text-sm">
  <div class="w-32 h-32 border-2 border-dotted border-blue-500">
    <div v-if="images" class="w-full h-full flex items-center">
      <img :src="images" alt="image">
    </div>
    <div v-else class="w-full h-full flex items-center justify-center cursor-pointer hover:bg-pink-100"
          @click="clickInputTag()"
          @drop.prevent="dropInputTag($event)"
          @dragover.prevent>
      <input ref="image" id="input"
             type="file" name="image" accept="image/*" multiple="multiple"
             class="hidden"
             @change="uploadImage()">
      <svg class="w-8 h-8" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v3m0 0v3m0-3h3m-3 0H9m12 0a9 9 0 11-18 0 9 9 0 0118 0z" />
      </svg>
    </div>
  </div>
</div>
</template>

 먼저 추가된 코드는 input 태그 바로 위에 div 태그에 @drop.prevent와 @dragover.prevent 입니다. 요 두 가지 이벤트만 등록해두면 이미지를 드래그해서 갖다 놓을 수 있게 됩니다. 참 쉽죠? 그리고 drop event가 발생했을 때 dropInputTag 메소드가 실행되면서 인자로 event를 전달해서 업로드할 이미지의 정보를 읽을 수 있게 합니다.

<script>
import axios from 'axios'

export default {
  data: ()=>({
    images: ''
  }),
  methods: {
    uploadImage: function(file) {
      let form = new FormData()
      let image = file || this.$refs['image'].files[0]
      
      form.append('image', image)

      axios.post('/upload', form, {
          header: { 'Content-Type': 'multipart/form-data' }
      }).then( ({data}) => {
        this.images = data
      })
      .catch( err => console.log(err))
    },
    dropInputTag: function(event) {
      let file = Array.from(event.dataTransfer.files, v => v)[0]
      this.uploadImage(file)
    },
    clickInputTag: function() {
      this.$refs['image'].click()
    }
  }
}
</script>

 위에서 drop event가 실행되면 dropInputTag 메소드에서 파일에 대한 정보를 읽습니다.

 

 event.dataTransfer.files에 이미지의 정보가 담겨있는데 이 배열이 "유사 배열"입니다. 유사 배열은 배열이지만 배열 같지 않은 이상한 녀석인데요. 이 유사 배열을 얕게 복사해서 배열처럼 사용할 수 있게 해주는 것이 Array.from 메소드입니다. 유사 배열에 대해 나중에 기회가 되면 더 자세히 포스팅하도록 하겠습니다(설명하려면 저도 공부를 더 해야 하기에...).

 

 어쨌든 이미지에 대한 정보를 file 변수에 넣었으니 그냥 원래 있던 uploadImage 메소드에 인자로 넣어서 전달해주겠습니다. 이전 포스팅에서와는 다르게 원래 uploadImage 메소드에 file이라는 인자를 넣어서, 인자가 전달이 되면 전달된 인자를 image변수에 넣어주고, 인자가 전달이 안되면 클릭해서 실행했을 때와 동일하게 image를 읽어오는 방법으로 구현했습니다.

 

 나머지는 똑같아서 따로 설명할 것도 없네요.


▶ BACKEND 코드는 이미지 업로드하기 #1 와 같습니다! 


 포스팅이 시리즈로 나누어져 있는 것이 의아해하시는 분들이 계실 것 같아서 말씀드립니다. 굳이 제가 코드를 나눠서 업로드하는 이유는 제가 배우는 입장이었을 때 이 방법이 가장 좋았기 때문입니다. 너무 길거나 여러 기능을 포함하는 코드는 보고도 어디가 어떻게 작동하는지 이해가 어렵더라구요.

 

 나중에 이미지 업로드 시리즈의 마지막 포스팅에서 제가 구현하려고 한 모든 기능이 들어간 코드를 포스팅할 예정입니다.

 

 그럼 다음에는 여러 개의 이미지 파일을 선택해서 한 번에 올리는 방법과, 올린 이미지를 삭제하는 방법을 포스팅하도록 하겠습니다.


세상에 고수는 많으니 저는 섬세한 컨셉으로

+ Recent posts