Programming/JavaScript

JavaScript / Vanilla JS :: input file 이미지 미리보기, 삭제 :: image preview and remove

고고마코드 2022. 10. 14. 13:16
반응형

input file 로 이미지 업로드를 하는 과정에서의 이미지 미리보기, 이미지 삭제 구현입니다.

input file multiple 은 아래 글을 참고하세요.
(준비중)


html

<div><input type="file" name="book_img" id="book_img" accept="image/*" required></div>
<div class="book-img-section" style="display:none;">
    <img class="book-img-preview" height="350px" src="이미지경로" 
        onerror="this.src='https://cdn.pixabay.com/photo/2018/01/04/15/51/404-error-3060993__340.png';"/>
    <button type="button" class="book-img-remove color_st05" onClick="">삭제</button>
</div>

input file 의 이름은 #_img 이고
각 class는 #-img-section, #-img-preview, #-img-remove 로 정하면 됩니다.
#에 원하는 네이밍을 부여하시면 됩니다. 이 부분이 아래에서 쓰일 tag 명칭이 됩니다.

src="이미지경로" 에 이미지가 있다면

src="이미지경로" 에 이미지가 없다면 #을 넣어주세요.

이렇게 나오도록 javascript 를 작성합니다.

에러 처리는 onerror로 해도 되고, js에서 이벤트 error를 감지해서 처리해도 됩니다.


javascript

js 코드 부분 설명

input file binding

const book_img_tag = "book";
const book_img_reader = new FileReader();
const book_img_file = document.querySelector('#'+book_img_tag+'_img');
book_img_file.addEventListener('change', function(e){handleSelected(e, this, book_img_reader, book_img_tag)});
if(document.querySelector('.'+book_img_tag+'-img-preview').getAttribute('src') != "#") {
    document.querySelector('.'+book_img_tag+'-img-section').style.display = "block";
    book_img_file.required = false;
}
document.querySelector('.'+book_img_tag+'-img-remove').addEventListener("click", () => { 
    removeImage(book_img_file, book_img_tag);
});

img_tag는 위의 html에서 지정한 tag 명칭과 동일하게 주면 됩니다.

FileReader는 input file 로 입력되는 파일을 비동기적으로 확인할 수 있습니다.
예제에서는 FileReader로 업로드하려는 이미지를 미리보기에 바로 보여주는 방식으로 활용합니다.
💣예제에 관련된 내용만 설명했고, 자세한 설명은 아래 문서를 참고하세요.
developer.mozilla.org - FileReader

이제 input file 이 등록/변경 되었을 때 이벤트 처리를 해주면 됩니다.
book_img_file.addEventListener('change', function(e){handleSelected(e, this, book_img_reader, book_img_tag)});
해당 부분이 이벤트 'change'에 반응하는 handler를 지정하는 부분입니다.
여러 이미지를(여러 개의 input file) 업로드해야 하는 경우를 고려해서 reader, tag를 파라미터에 함께 넘깁니다.

삭제 버튼의 'click' 이벤트 발생 시 이미지를 삭제하는 부분도 추가합니다.
만약 error 체크까지 해야 한다면, 이벤트 'error'에 핸들러를 추가해 코드를 작성하면 됩니다.

input file event listener

function addListeners(reader, fileTag) {
    reader.addEventListener('load', function(e){handleEvent(e, reader, fileTag)});
}

function handleSelected(e, fileInput, reader, fileTag) {
    const selectedFile = fileInput.files[0];
    if (selectedFile) {
        addListeners(reader, fileTag);
        reader.readAsDataURL(selectedFile);
    }
}

위에서 input file의 이벤트 발생 시, this로 file 객체를 함께 넘겨주었습니다.
fileInput.files[0]로 선택한 파일을 가져올 수 있습니다.

선택된 파일이 있다면, reader에 리스너를 추가하고, readAsDataURL로 파일의 내용을 읽어들입니다.

event handler

function handleEvent(event, reader, fileTag) {
    if (event.type === "load") { // 이미지 로드 시 미리보기 경로 설정
        document.querySelector('img.'+fileTag+'-img-preview').setAttribute('src', reader.result);
        document.querySelector('.'+fileTag+'-img-section').style.display = "block";
    }
}

실제 이벤트 처리 부분입니다.
미리보기 src를 세팅하고 화면에 출력합니다.

file remove

function removeImage(fileInput, fileTag) {
    document.querySelector('.'+fileTag+'-img-section').style.display = "none";
    document.querySelector('.'+fileTag+'-img-preview').setAttribute('src', '#');
    fileInput.value = '';
    fileInput.required = true;
}

등록한 이미지와 미리보기를 제거하는 부분입니다.


js 전체 코드

<script>
    /** START :: 이미지 관련 **/
    (function() {
        // 이벤트 핸들러 
        function handleEvent(event, reader, fileTag) {
            if (event.type === "load") { // 이미지 로드 시 미리보기 경로 설정
                document.querySelector('img.'+fileTag+'-img-preview').setAttribute('src', reader.result);
                document.querySelector('.'+fileTag+'-img-section').style.display = "block";
            }
        }

        // FileReader에 이벤트 핸들러 추가
        function addListeners(reader, fileTag) {
            // reader.addEventListener('loadstart', function(e){handleEvent(e, reader, fileTag)});
            reader.addEventListener('load', function(e){handleEvent(e, reader, fileTag)});
            // reader.addEventListener('loadend', function(e){handleEvent(e, reader, fileTag)});
            // reader.addEventListener('progress', function(e){handleEvent(e, reader, fileTag)});
            // reader.addEventListener('error', function(e){handleEvent(e, reader, fileTag)});
            // reader.addEventListener('abort', function(e){handleEvent(e, reader, fileTag)});
        }

        // 이미지 파일에 핸들러 추가
        function handleSelected(e, fileInput, reader, fileTag) {
            const selectedFile = fileInput.files[0];
            if (selectedFile) {
                addListeners(reader, fileTag);
                reader.readAsDataURL(selectedFile);
            }
        }

        // 이미지 제거
        function removeImage(fileInput, fileTag) {
            document.querySelector('.'+fileTag+'-img-section').style.display = "none";
            document.querySelector('.'+fileTag+'-img-preview').setAttribute('src', '#');
            fileInput.value = '';
            fileInput.required = true;
        }

        // 파일 바인딩 (실제로 수정해야 하는 부분)
        const book_img_tag = "book";
        const book_img_reader = new FileReader();
        const book_img_file = document.querySelector('#'+book_img_tag+'_img');
        book_img_file.addEventListener('change', function(e){handleSelected(e, this, book_img_reader, book_img_tag)});
        if(document.querySelector('.'+book_img_tag+'-img-preview').getAttribute('src') != "#") {
            document.querySelector('.'+book_img_tag+'-img-section').style.display = "block";
            book_img_file.required = false;
        }
        document.querySelector('.'+book_img_tag+'-img-remove').addEventListener("click", () => { 
            removeImage(book_img_file, book_img_tag);
        });
    })();
    /** END :: 이미지 관련 **/
</script>

참고자료

🔥developer.mozilla.org
javascript 코드를 참고하였으며, 필요한 방식으로 변형했습니다.

🔥pixabay.com
샘플 이미지를 사용했습니다.

🔥placeimg.com
샘플 이미지를 사용했습니다.

반응형