input 태그가 아닌 임의의 영역에 이벤트를 적용시켜 드래그 앤 드롭 기능을 구현해보겠습니다.
해당 기능을 구현하기 위해서는 아래의 이벤트를 사용하게 됩니다.
- drop - 드래그한 파일이 영역에 드롭(드래그한 객체를 놓았을 때)되었을 때 발생
- dragover - 드래그한 파일이 영역에 머물러 있을 때 발생
- dragenter - 드래그한 파일이 영역에 최초로 진입했을 때 발생
- dragleave - 드래그한 파일이 역영에 벗어났을 때 발생
그중 drop, dragover 이벤트는 필수로 사용해야 하는 이벤트입니다.
( dragover 이벤트를 적용하지 않으면 drop 이벤트가 작동하지 않음 )
코드
<div class="dropBox">
<h1>이곳에 파일을 드롭해주세요. </h1>
</div>
먼저 파일을 드롭할 영역을 만들어 줍니다.
그 후 자바스크립트 코드로 해당 태그에 drop, dragover 이벤트를 적용해 줍니다.
const $drop = document.querySelector(".dropBox");
// 드래그한 파일 객체가 해당 영역에 놓였을 때
$drop.ondrop = (e) => {
e.preventDefault();
// 드롭된 파일 리스트 가져오기
const files = [...e.dataTransfer?.files];
console.log(files);
}
// ondragover 이벤트가 없으면 onDrop 이벤트가 실핻되지 않습니다.
$drop.ondragover = (e) => {
e.preventDefault();
}
해당 코드에서 가장 중요한 부분은 preventDefault 메서드로 이벤트 동작을 방지하는 부분과 dataTransfer 데이터에 담겨있는 file 정보를 가져오는 부분입니다.
먼저 preventDefault 메서드로 이벤트 동작을 방지하지 않을 시 파일을 드래그, 드롭하는 과정에서 파일이 그대로 브라우저에 실행되는 문제가 발생할 수 있습니다.
드롭된 파일은 드롭 이벤트 객체의 dataTransfer 데이터에 담겨옵니다.
해당 데이터의 files로 접근할 시 드롭된 파일 정보를 가져올 수 있습니다.
이때 File 정보는 FileList에 담겨있습니다.
하지만 문제는 해당 정보는 Arrays 타입이 아니기에 for 문을 이용한 직접적인 접근이 아닌 이상 접근이 불가능합니다.
const files = e.dataTransfer?.files;
1. Array.from(files);
2. [...files];
해당 문제를 해결하기 위해 위 2가지의 방법을 소개하겠습니다. (둘 다 결과는 같습니다.)
두 개의 방법은 결국, 새로운 배열로 바꿔준다는 데에 있습니다.
드롭된 파일 리스트 띄우기
const $drop = document.querySelector(".dropBox");
const $title = document.querySelector(".dropBox h1");
// 드래그한 파일 객체가 해당 영역에 놓였을 때
$drop.ondrop = (e) => {
e.preventDefault();
// 파일 리스트
const files = [...e.dataTransfer?.files];
// 파일 리스트 띄위기
$title.innerHTML = files.map(file => file.name).join("<br>");
}
// ondragover 이벤트가 없으면 onDrop 이벤트가 실핻되지 않습니다.
$drop.ondragover = (e) => {
e.preventDefault();
}
해당 코드에서 추가된 코드는 단지 파일 리스트를 띄우는 부분입니다.
위에서 FileList 타입이 아닌 Arrays 타입으로 바꿔줌으로 map 메서드가 사용 가능해졌습니다.
File 데이터에 존재하는 파일명 정보만을 가져와 리스트를 띄워보았습니다.
시각적 효과 추가하기
드롭이 되기 전 해당 영역 위에 있으니 놓아도 된다는 시각적 반응 효과를 추가해보겠습니다.
이때는 제일 위에서 소개한 dragenter, dragleave 이벤트를 사용하면 해결됩니다.
/* 드롭 반응 */
.dropBox.active {
background: #eee;
}
미리 css에 효과 클래스를 추가해줍니다.
// 드래그한 파일이 최초로 진입했을 때
$drop.ondragenter = (e) => {
e.preventDefault();
$drop.classList.add("active");
}
// 드래그한 파일이 영역을 벗어났을 때
$drop.ondragleave = (e) => {
e.preventDefault();
$drop.classList.remove("active");
}
해당 코드에서도 똑같이 preventDefault 메서드를 사용해줍니다.
dragenter 이벤트가 발생하면 active라는 임의의 효과 클래스를 추가해주고, dragleave 이벤트가 발생하면 active 클래스를 제거하는 방식으로 효과를 줄 수 있습니다.
코드 예제