λ³Έλ¬Έ λ°”λ‘œκ°€κΈ°
πŸ“  archive

Vue.js와 Vuetify ν™œμš©ν•΄μ„œ axios둜 파일 μ—…λ‘œλ“œν•˜κΈ°

by HandHand 2021. 3. 1.

Vuetify?

VuetifyλŠ” Vue.jsλ₯Ό μœ„ν•œ λ””μžμΈ ν”„λ ˆμž„μ›Œν¬μž…λ‹ˆλ‹€.

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” Vue.js와 Vuetify λ₯Ό ν™œμš©ν•΄μ„œ μ„œλ²„μ— νŒŒμΌμ„ μ—…λ‘œλ“œν•˜λŠ” 방법에 λŒ€ν•΄ μ•Œμ•„λ³΄κ³ μž ν•©λ‹ˆλ‹€.

ν•΄λ‹Ή ν¬μŠ€νŒ…μ€ 사전에 파일 μ—…λ‘œλ“œλ₯Ό μ²˜λ¦¬ν•  수 μžˆλŠ” λ°±μ—”λ“œ μ„œλ²„κ°€ κ΅¬μ„±λ˜μ–΄μžˆλ‹€λŠ” μ „μž¬ν•˜μ— μ§„ν–‰λ©λ‹ˆλ‹€.

Vuetify File input μ»΄ν¬λ„ŒνŠΈ μ‚¬μš©

Vuetify μ—μ„œλŠ” 기쑴의 HTML input νƒœκ·Έ 역할을 ν•˜λŠ” μ—¬λŸ¬κ°€μ§€ μž…λ ₯ μ „μš© μ»΄ν¬λ„ŒνŠΈλ“€μ΄ μ‘΄μž¬ν•©λ‹ˆλ‹€.
이쀑 μ €ν¬λŠ” 파일 μ—…λ‘œλ“œλ₯Ό μœ„ν•œ v-file-input νƒœκ·Έλ₯Ό ν™œμš©ν•©λ‹ˆλ‹€.

Product.vue

v-file-input μ»΄ν¬λ„ŒνŠΈ

v-file-input 은 μ„ νƒλœ νŒŒμΌμ— 변경이 μžˆλ‹€λ©΄ change 이벀트λ₯Ό 톡해 μ›ν•˜λŠ” μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
ν•΄λ‹Ή 이벀트 핸듀링 ν•¨μˆ˜λ₯Ό 등둝해쀀 λ’€ μ„ νƒλœ νŒŒμΌμ„ 좔적할 수 μžˆλ„λ‘ ν•©λ‹ˆλ‹€.

<template>
  <div>
    μƒν’ˆ λ“±λ‘ν•˜κΈ°

    <v-file-input label="File input" @change="selectFile"></v-file-input>

    <v-btn @click="submit">μ„œλ²„μ— μ „μ†‘ν•˜κΈ°</v-btn>
  </div>
</template>

파일 정보λ₯Ό μ €μž₯ν•  데이터 μ„ μ–Έ

μ„ νƒλœ 파일 객체λ₯Ό 관리할 데이터 속성을 μ„ μ–Έν•΄μ€λ‹ˆλ‹€.

data() {
    return {
      image: '',
    }
  },

파일 선택 이벀트 처리

μ•žμ„œ change 이벀트 ν•Έλ“€λŸ¬ ν•¨μˆ˜λ‘œ λ“±λ‘ν•œ selectFile ν•¨μˆ˜μ—μ„œλŠ” 인자둜 μ„ νƒλœ 파일 객체λ₯Ό μ „λ‹¬λ°›μŠ΅λ‹ˆλ‹€.
ν•΄λ‹Ή 객체λ₯Ό data 의 image 에 ν• λ‹Ήν•΄μ€λ‹ˆλ‹€.

  // 파일 λ³€κ²½ μ‹œ 이벀트 ν•Έλ“€λŸ¬
  selectFile(file) {
    this.image = file;
  },

axios 둜 μ„œλ²„μ— 파일 μ—…λ‘œλ“œν•˜κΈ°

이제 μ„ νƒλœ νŒŒμΌμ„ μ „μ†‘ν•˜κΈ° μœ„ν•΄ formData λ₯Ό μƒμ„±ν•©λ‹ˆλ‹€.
axios 의 μš”μ²­ 인자둜 μ„œλ²„ api μ£Όμ†Œλ₯Ό μ§€μ •ν•˜κ³  Node.js의 multer λͺ¨λ“ˆμ„ μœ„ν•΄
Content-Type 을 multipart/form-data 둜 μ§€μ •ν•΄μ€¬μŠ΅λ‹ˆλ‹€.

async submit() {
      const formData = new FormData();
      formData.append('image', this.image);

      try {
        const { data } = await axios.post('http://127.0.0.1:3000/product/create', formData, {
          headers: {
            'Content-Type': 'multipart/form-data'
            }
          });
        console.log(data);
      } catch(err) {
        console.log(err);
      }
  }

전체 μ½”λ“œ

<template>
  <div>
    μƒν’ˆ λ“±λ‘ν•˜κΈ°

    <v-file-input label="File input" @change="selectFile"></v-file-input>

    <v-btn @click="submit">μ„œλ²„μ— μ „μ†‘ν•˜κΈ°</v-btn>
  </div>
</template>
import axios from "axios";

export default {
  data() {
    return {
      image: "test image",
    };
  },

  methods: {
    async submit() {
      const formData = new FormData();
      formData.append("image", this.image);

      try {
        const { data } = await axios.post(
          "http://127.0.0.1:3000/product/create",
          formData,
          {
            headers: {
              "Content-Type": "multipart/form-data",
            },
          }
        );
        console.log(data);
      } catch (err) {
        console.log(err);
      }
    },

    // 파일 λ³€κ²½ μ‹œ 이벀트 ν•Έλ“€λŸ¬
    selectFile(file) {
      this.image = file;
    },
  },
};

μ‹€ν–‰ κ²°κ³Ό(μ„œλ²„ 둜그)

POST /product/create 200 11.313 ms - 129
OPTIONS /product/create 204 0.205 ms - 0
{
  image: 'profile-1590918594170.jpg',
}

참고 자료

λ°˜μ‘ν˜•

πŸ’¬ λŒ“κΈ€