IT/development

[Vue.js] Vue.js ์ฒจ๋ถ€ํŒŒ์ผ ์—…๋กœ๋“œ

์•Œ ์ˆ˜ ์—†๋Š” ์‚ฌ์šฉ์ž 2023. 8. 13.

upload.html

<div id="app">
<!-- ์ฒจ๋ถ€ํŒŒ์ผ ์˜์—ญ ์˜ˆ์‹œ -->
<div class="field-head">
์ฒจ๋ถ€ํŒŒ์ผ<span class="text-red"></span>
<span id="extensions" class="text-red">[.jpg, .jpeg, .png, .xlsx, .hwp, .docx, .pptx, .pdf]</span>
    <div class="util-box">
    	<!-- ํŒŒ์ผ ๋ฐฐ์—ด์ด 5๊ฐœ๋ณด๋‹ค ํฌ๋ฉด ๋น„ํ™œ์„ฑํ™” --> <!-- @click.prevent๋กœ aํƒœ๊ทธ์˜ ๊ธฐ๋ณธ๊ฐ’์„ ๋ง‰๋Š”๋‹ค. -->
        <a href="#" :disabled="files.length >= 5" @click.prevent="addAttachFile"><span class="material-icons">add</span></a>
        <a href="#" @click.prevent="removeAttachFile"><span class="material-icons">remove</span></a>
    </div>
</div>
<div class="field-box" id="fileBox">
	<!-- hasAttachment๊ฐ€ false์ผ ๋•Œ๋งŒ ํ‘œ์‹œ๋œ๋‹ค. -->
    <div class="a_c bg-light" v-show="!hasAttachment"> <br>
        ํ™•์žฅ์ž๋Š” .jpg, .jpeg, .png, .xlsx, .hwp, .docx, .pptx, .pdf ๋งŒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. <br>
        5MB์ดํ•˜ ํŒŒ์ผ๋งŒ ์˜ฌ๋ ค์ฃผ์„ธ์š”.
    </div>
    
    <!-- ์—ฌ๊ธฐ๊ฐ€ ํ•ต์‹ฌ -->
    <ul classname="file-list">
    	<!-- Vue.js์˜ ์ธ์Šคํ„ด์Šค์˜ files ํฌ๊ธฐ๋งŒํผ ๋ฃจํ”„ -->
        <li v-for="(item, index) in files" :key="index">
            <div class="flex-box frm-file mt05">
                <span>{{ item.num  }}</span><span class="mr5">.์ฒจ๋ถ€</span>
                <!-- file1, file2, file3 ์ด๋Ÿฐ์‹์œผ๋กœ ์„ธํŒ…ํ•˜๊ธฐ ์œ„ํ•จ์ด๋‹ค. -->
                <input type="text" ref="'file' + item.num" title="" class="input-default file-txt">
                <input type="file"
                       :id="'filefrm' + item.num"
                       ref="'filefrm' + item.num"
                       class="btn-file"
                       title="ํŒŒ์ผ์ฐพ๊ธฐ"
                       accept=".jpg, .jpeg, .png, .xlsx, .hwp, .docx, .pptx, .pdf"
                       <!-- ์ฒด์ธ์ง€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ ์—ฐ๊ฒฐ -->
                       @change="handleFileChange($event, index)"
                >
                <label :for="'filefrm' + item.num">ํŒŒ์ผ ์ฒจ๋ถ€</label>
            </div>
        </li>
    </ul>
</div>
</div>

<button type="button" @click="reg" class="btn btn-normal">์ €์žฅ</button>


<script>

// ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ํŽธ์ง‘ํ•ด์„œ {} ์—ด๊ณ  ๋‹ซ๋Š”๊ฒŒ ์•ˆ ๋งž์„ ์ˆ˜๋„ ์žˆ์Œ
new Vue({
       //element id
       el: '#app',
       //vue์—์„œ ๊ด€๋ฆฌํ•  ๋ฐ์ดํ„ฐ
       data: { files: [], //์ฒจ๋ถ€ํŒŒ์ผ 
       		   hasAttachment: false,	// flag ์šฉ๋„
       },
       methods: {
           /**
            * ๋“ฑ๋ก
            */
           reg() {
             const self = this;     // ์ธ์Šคํ„ด์Šค ์ฐธ์กฐ ๋ณ€์ˆ˜
             if (confirm("๋“ฑ๋ก์„ ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?")) {
                 //formdata ์ƒˆ๋กœ์šด ๊ฐ์ฒด ์ƒ์„ฑ
                 const formData = new FormData();
                   //์ฒจ๋ถ€ํŒŒ์ผ ์„ธํŒ…
                   for (const fileData of this.files) {
                       if (fileData.file) {
                           formData.append('files', fileData.file);
                       }
                    }
                    
                    const url = '/api/file';
                    
                    //post http request
                    axios.post(url, formData, {
                            headers: { 'Content-Type': 'multipart/form-data' }
                       })
                      .then(function(response) {
                          console.log(response.data.code);
                          if(response.data.code === '1') {
                            alert("๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
                            location.href = "/";
                          } else {
                            alert("๋“ฑ๋ก์— ์‹คํŒจ ํ–ˆ์Šต๋‹ˆ๋‹ค.");
                          }
                      }.bind(this))
                        .catch(function(error) {
                          alert("๋“ฑ๋ก์— ์‹คํŒจ ํ–ˆ์Šต๋‹ˆ๋‹ค.");
                          console.log(error);
                        });
                    }
              }
           },
           /**
           * ์ฒจ๋ถ€ํŒŒ์ผ ์˜์—ญ ์ถ”๊ฐ€
           */
           addAttachFile() {
                if(this.files.length >= 5) {
                    alert("์ฒจ๋ถ€ํŒŒ์ผ์€ 5๊ฐœ๊นŒ์ง€ ๋“ฑ๋ก ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค");
                    return false;
                }
               this.files.push({ name: `Files ${this.files.length + 1}`, file: null, num: this.files.length + 1});
               this.hasAttachment = true;
           },
           /**
           * ์ฒจ๋ถ€ํŒŒ์ผ ์˜์—ญ ์‚ญ์ œ
           */
           removeAttachFile() {
               if (this.files.length > 0) {
                    this.files.pop();
               }
               if (this.files.length === 0) {
                    this.hasAttachment = false;
               }
           },
           /**
            * ์„ ํƒ๋œ ์ฒจ๋ถ€ํŒŒ์ผ ์„ธํŒ…
            * @param event
            * @param index
            */
           handleFileChange(event, index) {
                const selectedFile = event.target.files[0];
                this.files[index].file = selectedFile;
            },
    });
</script>

์œ„ ์ฝ”๋“œ๋Š” ๋™์ ์œผ๋กœ ์ฒจ๋ถ€ํŒŒ์ผ ์˜์—ญ์„ ์ถ”๊ฐ€/์‚ญ์ œ ํ›„ ์ฒจ๋ถ€ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์˜ˆ์ œ์ด๋‹ค.

์ „์ฒด์ ์œผ๋กœ ํฌ์ŠคํŒ…์„ ์œ„ํ•ด ํŽธ์ง‘ํ•œ ์ฝ”๋“œ๋ผ์„œ ํƒœ๊ทธ ์—ด๊ณ  ๋‹ซ๊ณ  ์•ˆ ๋งž์„ ์ˆ˜๋„ ์žˆ๋‹ค.

์ฒจ๋ถ€ํŒŒ์ผ ๊ด€๋ จ ๋ฉ”์†Œ๋“œ๋Š” ์ด 4๊ฐœ์ด๋‹ค.

์ฒจ๋ถ€ํŒŒ์ผ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ด์„ ๋ฐฐ์—ด์ด ์ธ์Šคํ„ด์Šค์˜ data ๊ฐ์ฒด์•ˆ์— ์ดˆ๊ธฐํ™” ๋œ ์ƒํƒœ์ด๊ณ 

addAttachFile(), removeAttachFile()๋กœ data ๊ฐ์ฒด์˜ files ๋ฐฐ์—ด์˜ ๊ฐ’์„ ์ถ”๊ฐ€/์‚ญ์ œ ํ•œ๋‹ค.

๋ฐฐ์—ด์— ๊ฐ’์„ ์ถ”๊ฐ€/์‚ญ์ œ ํ›„ ํ™”๋ฉด์— ์—ฐ๊ฒฐํ•ด์ฃผ๋ฉด Vue.js์—์„œ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ๊ฐ์ง€๋ฅผ ํ•ด์„œ ์•Œ์•„์„œ ํ‘œ์‹œํ•ด์ค€๋‹ค.

์ถ”๊ฐ€ ์‹œ ๋ฐฐ์—ด์— name, file, num์„ ์ถ”๊ฐ€ํ•œ๋‹ค.

์ฒจ๋ถ€ํŒŒ์ผ ์˜์—ญ์—์„œ๋Š” ๋™์ ์œผ๋กœ ์„ค์ •๋˜๋Š” files๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋งŒํผ ๋ฃจํ”„๋ฅผ ๋Œ์•„์„œ ํ™”๋ฉด์— ๋ Œ๋”๋ง ๋˜๊ณ 

์ฒจ๋ถ€ํŒŒ์ผ ์ถ”๊ฐ€ ์‹œ handleFileChange() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ ํŒŒ์ผ์„ files ๋ฐฐ์—ด์— ์„ธํŒ… ํ›„

์„œ๋ฒ„ ์ „์†ก ์‹œ ์ฒจ๋ถ€ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ๋งŒํผ formData์— ์„ธํŒ… ํ›„ multipart/form-data ํƒ€์ž…์œผ๋กœ ๋ณด๋‚ด๊ณ 

๊ฒฐ๊ณผ์ฝ”๋“œ์— ๋”ฐ๋ผ ๋ถ„๊ธฐ์ฒ˜๋ฆฌํ•œ๋‹ค.

๋Œ“๊ธ€