파일첨부 기능을 개발, 10MB 이하의 PNG, JPG, JPEG, GIF, PDF 파일만 업로드할 수 있게 구현, 그리고 file이 업로드 시 input text에 file name을 출력 및 파일첨부의 기능은 다운로드 및 삭제로 대체,
<div>
<SInput class="mr-8" readonly w-size="xx-large" />
<SButton>파일 첨부</SButton>
<input type="file" class="is-blind"/>
</div>
//Input Components 구조 및 props data
<input
:value="value"
:placeholder="placeholder"
:readonly="readonly"
:class="{ 'is-error': isError }"
:style="{
minWidth: `${minWidth}rem`
}"
:type="type"
:maxlength="maxlength ? maxlength : '524288'"
@input="updateInput"
@keyup="keyup"
@keyup.enter="enter"
/>
<script>
export default {
name: 'SInput',
props: {
value: {
type: [String, Number],
required: false,
default: ''
},
placeholder: {
type: String,
required: false,
default: ''
},
type: {
type: String,
required: false,
default: 'text'
},
maxlength: {
type: String,
required: false,
default: ''
},
readonly: {
type: Boolean,
required: false,
default: false
},
// value: small | normal | large | x-large | xx-large | xxx-large
wSize: {
type: String,
required: false,
default: 'normal'
},
isError: {
type: Boolean,
required: false,
default: false
}
},
data() {
return {
minWidth: 20
};
},
created() {
let minWidth = 9.6;
switch (this.wSize) {
case 'small':
minWidth = 15.2;
break;
case 'normal':
minWidth = 20;
break;
case 'large':
minWidth = 32;
break;
case 'x-large':
minWidth = 46.0;
break;
case 'xx-large':
minWidth = 58.4;
break;
case 'xxx-large':
minWidth = 74.4;
break;
default:
minWidth = 20;
break;
}
this.minWidth = minWidth;
},
methods: {
updateInput(e) {
this.$emit('input', e.target.value);
},
keyup(e) {
this.$emit('keyup', e.target.value);
},
enter(e) {
this.$emit('enter', e.target.value);
}
}
};
</script>
input에 accept을 이용하여 확장자를 제한하고 readonly를 통하여 읽기전용으로 만들어준 후 ref를 통하여 button 클릭 시 input file과 연결 시키기 (input은 IR기법으로 숨김처리)
<div>
<SInput class="mr-8" readonly w-size="xx-large" />
<SButton @click="fileClick('fileUpload')">파일 첨부</SButton>
<input
ref="fileUpload"
type="file"
accept="image/jpg, image/jpeg, image/png, image/gif, .pdf"
class="is-blind"
/>
</div>
<script>
fileClick(target) {
this.$refs[target].click();
},
</script>
파일이 있으면 file.size를 계산하여 10MB 이하면 받아오는 api 실행 및 아닐 시 시스템 모달로 경고창 띄워주기를 작성,
<div>
<SInput class="mr-8" readonly w-size="xx-large" />
<SButton @click="fileClick('fileUpload')">파일 첨부</SButton>
<input
ref="fileUpload"
type="file"
accept="image/jpg, image/jpeg, image/png, image/gif, .pdf"
class="is-blind"
@change="fileChange($event, 0)"
/>
</div>
<script>
async fileChange(e, index) {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
const size = file.size / 1024 / 1024;
if (size <= 10) {
const formData = new FormData();
formData.append('files', file);
await this.$axios.$post('/file', formData).then((fileForm) => {
this.detailData.files[index] = fileForm;
});
} else {
this.modal.isFileError = true;
}
e.target.value = null;
e.target.files = null;
}
},
</script>
<div>
<SInput :value="getFileName(0)" class="mr-8" readonly w-size="xx-large" />
<SButton @click="fileClick('fileUpload')">파일 첨부</SButton>
<input
ref="fileUpload"
type="file"
accept="image/jpg, image/jpeg, image/png, image/gif, .pdf"
class="is-blind"
@change="fileChange($event, 0)"
/>
</div>
<script>
async fileChange(e, index) {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
const size = file.size / 1024 / 1024;
if (size <= 10) {
const formData = new FormData();
formData.append('files', file);
await this.$axios.$post('/file', formData).then((fileForm) => {
this.detailData.files[index] = fileForm;
});
} else {
this.modal.isFileError = true;
}
e.target.value = null;
e.target.files = null;
this.$forceUpdate();
}
},
getFileName(index) {
return this.detailData.files[index]?.originalFileName || '';
},
</script>
<div>
<SInput :value="getFileName(0)" class="mr-8" readonly w-size="xx-large" />
<SButton v-if="!detailData.files[0]" @click="fileClick('fileUpload')">파일 첨부</SButton>
<template v-else>
<a
:href="`/api/file/download?path=${detailData.files[0].savedFileName}&fileName=${detailData.files[0].originalFileName}`"
download
class="download primary mr-8"
>다운로드</a
>
<SButton @click="onDeleteFile(0)">삭제</SButton>
</template>
<input
ref="fileUpload"
type="file"
accept="image/jpg, image/jpeg, image/png, image/gif, .pdf"
class="is-blind"
@change="fileChange($event, 0)"
/>
</div>
<script>
onDeleteFile(index) {
this.detailData.files[index] = null;
this.$forceUpdate();
},
</script>
받아온 data를 v-for로 작업 시 data값을 인자로 받아 처리
<div>{{ getState(item.state) }}</div>
<script>
getState(state) {
return state === 'SCHEDULE' ? '진행예정' : state === 'PROGRESS' ? '진행' : '종료';
}
</script>
v-for로 작성시,
<div v-for="(item, index) in 3" :key="item.index">
<SInput :value="getFileName(index)" class="mr-8" readonly w-size="xx-large" />
<SButton v-if="!detailData.files[index]" @click="fileClick(index)">파일 첨부</SButton>
<template v-else>
<a
:href="`/api/file/download?path=${detailData.files[index].savedFileName}&fileName=${detailData.files[index].originalFileName}`"
download
class="download primary mr-8"
>다운로드</a
>
<SButton @click="onDeleteFile(index)">삭제</SButton>
</template>
<input
ref="fileUpload"
type="file"
accept="image/jpg, image/jpeg, image/png, image/gif, .pdf, .zip"
class="is-blind"
multiple
@change="fileChange($event, index)"
/>
</div>
<script>
methods: {
async fileChange(e, index) {
if (e.target.files && e.target.files[0]) {
const file = e.target.files[0];
const size = file.size / 1024 / 1024;
if (size <= 10) {
const formData = new FormData();
formData.append('files', file);
await this.$axios.$post('/file', formData).then((fileForm) => {
this.detailData.files[index] = fileForm;
});
} else {
this.modal.isFileError = true;
}
e.target.value = null;
e.target.files = null;
this.$forceUpdate();
}
},
fileClick(index) {
this.$refs.fileUpload[index].click();
},
getFileName(index) {
return this.detailData.files[index]?.originalFileName || '';
},
onDeleteFile(index) {
this.detailData.files[index] = null;
this.$forceUpdate();
}
}
</script>
이미지 업로드 미리보기,
<script>
thumb(event) {
const input = event.target;
if (input.files && input.files[0]) {
const reader = new FileReader();
reader.onload = (e) => {
this.uploadImageFile = e.target.result;
};
reader.readAsDataURL(input.files[0]);
}
},
</script>