자바스크립트로 Image Upload 및 Preview 구현하기
중고나라 클론 프로젝트를 하면서 처음 해보는 이미지 업로드 기능에 부딪혔다.
여기저기 정보를 찾아보면서 공부한 내용을 정리해보려고 한다.
그리고 단순 input에 받는것이 아닌 다른 요소(div 등..)를 눌렀을 때 이미지 업로드와 동시에 preview 화면도 구현한다.
해당 포스트에 있는 코드는 이해를 돕기위해 코드를 모두 html 파일 내부에 작성했다.
실제 프로젝트에서는 html, css, js를 모두 나눠서 작업했다.
● HTML 에서 이미지를 업로드 받는방법
<input type="file" class="real-upload" accept="image/*" required multiple>
input type속성을 file로 정의하면 파일 업로드가 가능해진다.
또한 accept 속성을 img/*으로 지정할 경우 이미지 파일만 업로드가 가능해진다.
● 다른 요소(div 등..) 클릭시 input 이벤트가 발생하게 하는방법
내가 구현하고자 하는것은 div 를 눌렀을 때 input 의 파일선택창이 뜨는것이다.
이를 위해 input 은 display: none; 속성으로 숨기고 div에 대해서 input을 클릭하는 이벤트를 추가했다.
<body>
<input type="file" class="real-upload" accept="image/*" required multiple style="display: none;">
<div class="upload"></div>
<script>
const realUpload = document.querySelector('.real-upload');
const upload = document.querySelector('.upload');
upload.addEventListener('click', () => realUpload.click());
</script>
</body>
위 사진처럼 input 태그의 "파일 선택" 버튼을 누르지 않아도 잘 출력된다.
● input 태그에서 업로드한 파일을 다루는 방법
input 에 파일이 업로드되면 change event 가 발생하게 된다.
DOM.addEventListener 를 통해서 change event 를 지정하고 getImageFiles 함수를 등록했다.
<head>
<meta charset="UTF-8">
<style>
.real-upload {
display: none;
}
.upload {
width: 200px;
height: 200px;
background-color: antiquewhite;
}
</style>
</head>
<body>
<input type="file" class="real-upload" accept="image/*" required multiple>
<div class="upload"></div>
<script>
function getImageFiles(e) {
const files = e.currentTarget.files;
console.log(typeof files, files);
}
const realUpload = document.querySelector('.real-upload');
const upload = document.querySelector('.upload');
upload.addEventListener('click', () => realUpload.click());
realUpload.addEventListener('change', getImageFiles);
</script>
</body>
object 형식의 FileList 가 생성되었으며 출력시 위 처럼 출력된다.
● input 태그에서 업로드된 파일의 유효성검사 방법
우선 업로드된 이미지 파일의 갯수를 체크하는 방법이다.
유사배열인 FileList 를 ES6 Spread 문법을 통해 Array로 변환하여 length 메서드로 길이를 체크하는 방식이다.
function getImageFiles(e) {
const files = e.currentTarget.files;
if ([...files].length >= 7) {
alert('이미지는 최대 6개까지 업로드가 가능합니다.');
return;
}
}
다음은 업로드된 파일이 이미지 파일인지 체크하는 방법이다.
동일하게 유사배열인 FileList를 스프레드 문법을 통해 Array 로 변환해서 forEach 함수로 값을 체크한다.
function getImageFiles(e) {
const files = e.currentTarget.files;
[...files].forEach(file => {
if (!file.type.match("image/.*")) {
alert('이미지 파일만 업로드가 가능합니다.');
return;
}
})
}
!file.type.match("image/.*") 를 통해서 file 이 이미지인지 체크했다. 만약 이미지가 아닐경우 alert 를 띄우는 형식이다.
● 업로드된 이미지 파일 preview 표현하기
위에서 작성한 코드를 바탕으로 최종 코드를 완성했다. 로직은 아래와 같다
- div 를 눌렀을때 <input type="file"> 이 클릭되게 이벤트를 추가
- 업로드된 파일이 6개 이상인지 검사한다. 7개부터는 업로드가 불가능하다.
- 업로드된 파일이 모두 이미지 형식인지 검사한다.
- 이미지 파일을 li 태그내에 넣어서 ul 태그에 추가한다.
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
li {
list-style: none;
}
img {
width: 200px;
height: 200px;
}
.real-upload {
display: none;
}
.upload {
width: 200px;
height: 200px;
background-color: antiquewhite;
}
.image-preview {
width: 1300px;
height: 200px;
background-color: aquamarine;
display: flex;
gap: 20px;
}
</style>
</head>
<body>
<input type="file" class="real-upload" accept="image/*" required multiple>
<div class="upload"></div>
<ul class="image-preview"></ul>
<script>
function getImageFiles(e) {
const uploadFiles = [];
const files = e.currentTarget.files;
const imagePreview = document.querySelector('.image-preview');
const docFrag = new DocumentFragment();
if ([...files].length >= 7) {
alert('이미지는 최대 6개 까지 업로드가 가능합니다.');
return;
}
// 파일 타입 검사
[...files].forEach(file => {
if (!file.type.match("image/.*")) {
alert('이미지 파일만 업로드가 가능합니다.');
return
}
// 파일 갯수 검사
if ([...files].length < 7) {
uploadFiles.push(file);
const reader = new FileReader();
reader.onload = (e) => {
const preview = createElement(e, file);
imagePreview.appendChild(preview);
};
reader.readAsDataURL(file);
}
});
}
function createElement(e, file) {
const li = document.createElement('li');
const img = document.createElement('img');
img.setAttribute('src', e.target.result);
img.setAttribute('data-file', file.name);
li.appendChild(img);
return li;
}
const realUpload = document.querySelector('.real-upload');
const upload = document.querySelector('.upload');
upload.addEventListener('click', () => realUpload.click());
realUpload.addEventListener('change', getImageFiles);
</script>
</body>
위 코드를 기준으로 현재 진행중인 프로젝트에 적용했다. 이미지 업로드시 아래와 같이 표현된다.