문제 상황: 창 밖으로 드래그되는 순간을 감지하고 싶다면
파일이나 요소를 브라우저 창에 드래그한 뒤, 다시 창 바깥으로 빠져나가는 시점을 정확히 감지해야 하는 경우가 있습니다. 특히 Firefox에서는 dragleave 이벤트가 자식 요소 사이를 오갈 때마다 반복해서 발생하기 때문에, 이벤트를 단순히 한 번만 듣는 방식으로는 의도한 동작을 구현하기 어렵습니다.
해결 원리: dragenter / dragleave 대상 요소 추적
핵심은 dragenter와 dragleave 이벤트가 실제로 어떤 요소에서 발생했는지 추적하는 것입니다. 개별 요소에 이 두 이벤트를 등록하면 해당 요소에서 발생한 이벤트뿐만 아니라 자식 요소에서 발생한 이벤트까지 모두 캡처됩니다.
따라서 현재 드래그 중인 요소들의 집합(collection)을 관리하고, 이 집합이 완전히 비는 시점을 드래그가 창을 완전히 벗어난 순간으로 판단하면 됩니다.
draghover 플러그인 구현 코드
아래는 위 원리를 jQuery 플러그인 형태로 구현한 draghover 코드입니다.
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(ev) {
if (collection.length === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(ev.target);
});
self.on('dragleave drop', function(ev) {
collection = collection.not(ev.target);
if (collection.length === 0) {
self.trigger('draghoverend');
}
});
});
};
동작 방식
- dragenter 발생 시: 추적 집합이 비어 있던 상태(첫 진입)라면
draghoverstart커스텀 이벤트를 발생시키고, 해당 요소를 집합에 추가합니다. - dragleave 또는 drop 발생 시: 해당 요소를 집합에서 제거하고, 집합이 비면(드래그 대상이 모든 요소를 벗어나면)
draghoverend커스텀 이벤트를 발생시킵니다.
플러그인 사용 예시
이제 window 객체에 플러그인을 적용하고 커스텀 이벤트를 리스닝하면 됩니다.
$(window).draghover().on({
'draghoverstart': function() {
alert('창 안으로 드래그했습니다');
},
'draghoverend': function() {
alert('창 밖으로 드래그했습니다');
}
});
이 방식을 사용하면 드래그 항목이 창 안으로 들어오는 순간과 완전히 창 밖으로 벗어나는 순간을 Firefox를 포함한 주요 브라우저에서 안정적으로 감지할 수 있습니다.