안녕하세요. 이번 시간에는 드래그 드롭 api에 대해 알아보겠습니다. 지난 시간에 배운 File API와 같이 사용하면 좋습니다. 보통 파일을 특정 구역에 드롭해서 업로드하기 때문이죠.
우선 HTML 태그를 드래그하는 방법부터 알아보죠. 보통 태그들은 드래그할 수 없습니다. 하지만 태그의 속성으로 draggable="true"를 주면 그제서야 드래그가 되기 시작합니다. 그리고 드롭할 구역이 필요하겠죠? 드롭할 구역에는 JS로 ondragover과 ondrop 이벤트 핸들러를 연결해주어야 합니다.
위와 같이 드래그 후 드롭할 수 있습니다. 그 와중에 데이터를 전달할 수 있습니다. JS 부분을 보시면
document.getElementById('drag').ondragstart = function() {
e.dataTransfer.setData('data', this.innerHTML); // 드래그해보세요 문자열 전달
};
document.getElementById('drop').ondragover = function(e) {
e.preventDefault(); // 필수 이 부분이 없으면 ondrop 이벤트가 발생하지 않습니다.
};
document.getElementById('drop').ondrop = function() {
alert(e.dataTransfer.getData('data')); // 데이터를 가져옵니다.
};
dragstart 이벤트핸들러에서 e.dataTransfer.setData
로 전달할 데이터를 지정해줍니다. setData는 키-값 형식으로 저장하기 때문에, 키만 다르면 여러 개의 데이터를 저장할 수 있습니다. dragover이벤트에서는 e.preventDefault()
로 drop 이벤트가 호출될 수 있게 해주고요. drop 이벤트에서 e.dataTransfer.getData
로 데이터를 받을 수 있습니다.
이번에는 파일을 직접 드롭해보죠. 아무 파일이나 끌어서 아래에 넣어보세요.
var drop = document.getElementById('drop');
drop.ondragover = function(e) {
e.preventDefault(); // 이 부분이 없으면 ondrop 이벤트가 발생하지 않습니다.
};
drop.ondrop = function(e) {
e.preventDefault(); // 이 부분이 없으면 파일을 브라우저 실행해버립니다.
var data = e.dataTransfer;
if (data.items) { // DataTransferItemList 객체 사용
for (var i = 0; i < data.items.length; i++) { // DataTransferItem 객체 사용
if (data.items[i].kind == "file") { // 아이템 종류가 파일이면
var file = data.items[i].getAsFile(); // File API 사용
alert(file.name);
}
}
} else { // File API 사용
for (var i = 0; i < data.files.length; i++) {
alert(data.files[i].name);
}
}
};
아까와는 다르게 e.dataTransfer.items
와 e.dataTransfer.files
를 사용합니다. files 객체는 File API이기 때문에 그 강좌 에 나오는 대로 하면 드롭한 파일을 처리할 수 있습니다. 하지만 dataTransfer 객체에는 DataTransferItemList라는 특수한 객체가 있습니다. 구형 브라우저에서는 files 객체가 작동하지 않기 때문에 어쩔 수 없이 items 객체를 사용해야 합니다. 참고로 여러 개의 파일을 드롭하면 모두 받아지는데요. 그래서 위의 코드에서 for 문으로 DataTransferItemList를 DataTransferItem으로 나눠준 겁니다.
DataTransferItem 객체 안에는 kind와 type 속성이 있는데요. type은 png파일이면 'image/png' 이렇게 파일의 속성을 알려주고요. kind는 드롭한 것이 파일인지(file) 문자열인지(string) 알려줍니다. 위의 코드에서는 kind가 file일 때 getAsFile 메소드를 호출하라고 되어있습니다. 이 메소드를 호출하면 다시 File API에 해당하는 파일 객체를 반환합니다.
그렇다면 File API를 쓰면 되지 왜 굳이 DataTransferItem 객체를 사용하는 걸까요? 아까도 말씀드렸다시피 파일 말고도 문자열도 드롭할 수 있습니다. 문자열을 드롭하게 되면 kind는 string, type은 text/*가 되고요. 데이터는 getAsString 메소드로 받을 수 있습니다.
data.items[i].getAsString(function(s) {
console.log(s);
});
getAsFile과는 다르게 콜백 함수를 통해서 데이터를 받습니다. 문자열이 길 경우 등의 이유로 동기적으로 처리하기보다는 비동기적으로 처리하기로 한 것 같습니다.
드래그 앤 드롭의 단점은 모바일에서는 이 API를 사용할 수 없다는 겁니다. 하지만 모바일에서는 거의 드래그 앤 드롭을 쓸 일이 없기 때문에 그렇게 중요한 문제는 아닌 것 같습니다.
드래그 앤 드롭도 별 거 아니죠? 특히 File API와 같이 사용하면 쉽게 이미지 업로드를 할 수 있습니다. 다음 시간에는 이미지를 폼으로 업로드할 수 있는 FormData 객체에 대해 알아봅시다!