IT/development

[Vue.js] Vue.js 첨부파일 업로드

알 수 없는 사용자 2023. 8. 13. 21:31
반응형

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 타입으로 보내고

결과코드에 따라 분기처리한다.

반응형