https://codepen.io/loy124/pen/ZEbGQaW
codepen에도 업로드 해두었다.(테스트 가능)
프로젝트를 진행중에 파일을 업로드하기전 파일 업로드시 이미지 미리보기 를 나타내주는 컴포넌트가 필요해서 제작하게 되었다.
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://unpkg.com/vue/dist/vue.js"></script>
</head>
<body>
<div class="main-container">
<div class="room-deal-information-container">
<div class="room-deal-information-title">사진 등록</div>
<div class="room-picture-notice">
<ul class="room-write-wrapper">
<li>
사진은 가로로 찍은 사진을 권장합니다. (가로 사이즈 최소 800px)
</li>
<li>사진 용량은 사진 한 장당 10MB 까지 등록이 가능합니다.</li>
</ul>
</div>
<div class="room-file-upload-wrapper">
<div v-if="!files.length" class="room-file-upload-example-container">
<div class="room-file-upload-example">
<div class="room-file-image-example-wrapper">이미지</div>
<div class="room-file-notice-item">
실사진 최소 3장 이상 등록하셔야 하며, 가로사진을 권장합니다.
</div>
<div class="room-file-notice-item room-file-notice-item-red">
로고를 제외한 불필요한 정보(워터마크,상호,전화번호 등)가 있는 매물은 비공개처리됩니다
</div>
<div class="room-file-notice-item room-file-upload-button">
<div class="image-box">
<!-- <div class="image-profile">
<img :src="profileImage" />
</div>-->
<label for="file">일반 사진 등록</label>
<input type="file" id="file" ref="files" @change="imageUpload" multiple />
</div>
</div>
</div>
</div>
<div v-else class="file-preview-content-container">
<div class="file-preview-container">
<div v-for="(file, index) in files" :key="index" class="file-preview-wrapper">
<div class="file-close-button" @click="fileDeleteButton" :name="file.number">
x
</div>
<img :src="file.preview" />
</div>
<div class="file-preview-wrapper-upload">
<div class="image-box">
<label for="file">추가 사진 등록</label>
<input type="file" id="file" ref="files" @change="imageAddUpload" multiple />
</div>
<!-- <div class="file-close-button" @click="fileDeleteButton" :name="file.number">x</div> -->
</div>
</div>
</div>
</div>
</div>
</body>
</html>
js 파일
files.file 에는 실제 file의 데이터가 담겨있고
files.preview에는 프리뷰를 활용하기 위해 URL.createobjectURL을 활용해 프리뷰 이미지를 생성하였다.
const app = new Vue({
el: ".main-container",
data() {
return {
files: [], //업로드용 파일
filesPreview: [],
uploadImageIndex: 0 // 이미지 업로드를 위한 변수
}
},
methods: {
imageUpload() {
console.log(this.$refs.files.files);
// this.files = [...this.files, this.$refs.files.files];
//하나의 배열로 넣기
let num = -1;
for (let i = 0; i < this.$refs.files.files.length; i++) {
this.files = [
...this.files,
//이미지 업로드
{
//실제 파일
file: this.$refs.files.files[i],
//이미지 프리뷰
preview: URL.createObjectURL(this.$refs.files.files[i]),
//삭제및 관리를 위한 number
number: i
}
];
num = i;
//이미지 업로드용 프리뷰
// this.filesPreview = [
// ...this.filesPreview,
// { file: URL.createObjectURL(this.$refs.files.files[i]), number: i }
// ];
}
this.uploadImageIndex = num + 1; //이미지 index의 마지막 값 + 1 저장
console.log(this.files);
// console.log(this.filesPreview);
},
imageAddUpload() {
console.log(this.$refs.files.files);
// this.files = [...this.files, this.$refs.files.files];
//하나의 배열로 넣기c
let num = -1;
for (let i = 0; i < this.$refs.files.files.length; i++) {
console.log(this.uploadImageIndex);
this.files = [
...this.files,
//이미지 업로드
{
//실제 파일
file: this.$refs.files.files[i],
//이미지 프리뷰
preview: URL.createObjectURL(this.$refs.files.files[i]),
//삭제및 관리를 위한 number
number: i + this.uploadImageIndex
}
];
num = i;
}
this.uploadImageIndex = this.uploadImageIndex + num + 1;
console.log(this.files);
// console.log(this.filesPreview);
},
fileDeleteButton(e) {
const name = e.target.getAttribute('name');
this.files = this.files.filter(data => data.number !== Number(name));
// console.log(this.files);
},
}
});
css파일
.main-container {
width: 1200px;
height: 400px;
margin: 0 auto;
}
.room-deal-information-container {
margin-top: 50px;
color: #222222;
border: 1px solid #dddddd;
}
.room-deal-information-title {
text-align: center;
font-size: 18px;
line-height: 60px;
border-bottom: 1px solid #dddddd;
}
.room-deal-information-content-wrapper {
min-height: 50px;
display: flex;
}
.room-deal-informtaion-content-title {
font-size: 15px;
display: flex;
align-items: center;
justify-content: center;
width: 150px;
background-color: #f9f9f9;
}
.room-deal-information-content {
width: 100%;
font-size: 14px;
}
.room-deal-option-selector {
display: flex;
align-items: center;
padding: 15px;
}
.room-deal-option-item {
width: 100px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border: 1px solid #cccccc;
border-radius: 5px;
cursor: pointer;
}
.room-deal-option-item:last-child {
margin-left: 10px;
}
.room-deal-option-notice {
margin-left: auto;
font-size: 14px;
color: #888888;
}
.room-deal-option-item-deposit {
margin-left: 10px;
}
.room-deal-information-wrapper {
display: flex;
flex-direction: column;
}
.room-deal-information-option {
padding: 10px;
display: flex;
align-items: center;
}
.room-deal-information-option:last-child {
border-bottom: 1px solid #dddddd;
}
.room-deal-information-item-type {
font-size: 13px;
color: #fff;
background-color: #61b6e5;
min-width: 50px;
height: 26px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 3px;
}
.room-deal-information-item-wrapper {
display: flex;
align-items: center;
margin-left: 10px;
height: 46px;
width: 100%;
}
.room-deal-information-item-wrapper>input {
border: 1px solid #dddddd;
width: 140px;
height: 100%;
padding: 0 15px;
font-size: 15px;
}
.room-deal-inforamtion-won {
margin: 0 10px;
}
.room-deal-information-example {
color: #888888;
}
.room-deal-information-option:not(:first-child) {
margin-top: 10px;
}
.room-deal-inforamtion-divide {
font-size: 22px;
margin: 0 8px;
color: #222222;
font-weight: 100;
}
.room-deal-close-button-wrapper {
margin-left: auto;
cursor: pointer;
}
.room-deal-close-button {
display: flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
background-color: #666666;
color: rgb(220, 220, 220);
}
.room-deal-cliked {
background-color: rgb(235, 235, 235);
color: rgb(170, 170, 170);
}
.room-file-upload-example {
height: 100%;
}
.room-write-content-container {
border-top: 1px solid #dddddd;
min-height: 260px;
}
.room-picture-notice {
margin: 20px;
padding: 20px 40px;
border: 1px solid #dddddd;
}
.file-preview-content-container {
height: 100%;
}
.room-file-upload-wrapper {
margin: 20px;
border: 1px solid #dddddd;
background-color: #f4f4f4;
min-height: 350px;
font-size: 15px;
color: #888888;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.room-file-upload-example-container {
display: flex;
align-items: center;
justify-content: center;
/* height: 100%;
width: 100%; */
}
.room-file-image-example-wrapper {
text-align: center;
}
.room-file-notice-item {
margin-top: 5px;
text-align: center;
}
.room-file-notice-item-red {
color: #ef4351;
}
.image-box {
margin-top: 30px;
padding-bottom: 20px;
text-align: center;
}
.image-box input[type='file'] {
position: absolute;
width: 0;
height: 0;
padding: 0;
overflow: hidden;
border: 0;
}
.image-box label {
display: inline-block;
padding: 10px 20px;
background-color: #232d4a;
color: #fff;
vertical-align: middle;
font-size: 15px;
cursor: pointer;
border-radius: 5px;
}
.file-preview-wrapper {
padding: 10px;
position: relative;
}
.file-preview-wrapper>img {
position: relative;
width: 190px;
height: 130px;
z-index: 10;
}
.file-close-button {
position: absolute;
/* align-items: center; */
line-height: 18px;
z-index: 99;
font-size: 18px;
right: 5px;
top: 10px;
color: #fff;
font-weight: bold;
background-color: #666666;
width: 20px;
height: 20px;
text-align: center;
cursor: pointer;
}
.file-preview-container {
height: 100%;
display: flex;
flex-wrap: wrap;
}
.file-preview-wrapper-upload {
margin: 10px;
padding-top: 20px;
background-color: #888888;
width: 190px;
height: 130px;
}
.room-write-button-wrapper {
margin-top: 20px;
display: flex;
justify-content: center;
align-items: center;
color: #222222;
}
.room-write-button-wrapper>div {
width: 160px;
height: 50px;
border: 1px solid #dddddd;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
cursor: pointer;
}
.room-write-button {
margin-left: 15px;
color: #fff;
background-color: #1564f9;
}
.room-write-button:hover {
opacity: 0.8;
}
'Vue > vue 활용하기' 카테고리의 다른 글
vue Toast UI Editor 적용기 (1) | 2022.06.17 |
---|---|
Spring-boot(mysql-mybatis-aws s3(cloudFront) + Vue.js 를 활용한 파일 업로드 하기 - 프론트 구성 (0) | 2020.04.12 |