내가 겪고있는 문제 dragleave
는 요소의 하위 요소를 가리킬 때 요소 의 이벤트 가 시작된다는 것 입니다. 또한 dragenter
상위 요소를 다시 호버링 할 때 발생하지 않습니다.
나는 간단한 바이올린을 만들었습니다 : http://jsfiddle.net/pimvdb/HU6Mk/1/ .
HTML :
<div id="drag" draggable="true">drag me</div>
<hr>
<div id="drop">
drop here
<p>child</p>
parent
</div>
다음 JavaScript를 사용하십시오.
$('#drop').bind({
dragenter: function() {
$(this).addClass('red');
},
dragleave: function() {
$(this).removeClass('red');
}
});
$('#drag').bind({
dragstart: function(e) {
e.allowedEffect = "copy";
e.setData("text/plain", "test");
}
});
그것이해야 할 일은 div
무언가를 드래그 할 때 빨간색을 빨간색 으로 만들어 사용자에게 알리는 것입니다. 이것은 작동하지만 p
자식 으로 드래그하면 dragleave
해고되고 div
더 이상 빨간색이 아닙니다. 드롭으로 다시 이동 div
해도 다시 빨간색으로 표시되지 않습니다. 드롭에서 완전히 빠져 나와서 div
다시 끌어서 빨간색으로 만들어야합니다.
dragleave
자식 요소로 드래그 할 때 발생 하는 것을 막을 수 있습니까?
2017 업데이트 : TL; DR, pointer-events: none;
아래 @HD의 답변에 설명 된 최신 브라우저 및 IE11에서 작동 하는 CSS 를 찾으십시오 .
답변
당신은 참조 카운터를 유지하고 드래그를 얻을 때 증가하고 드래그 리브를 얻을 때 감소해야합니다. 카운터가 0에있을 때-클래스를 제거하십시오.
var counter = 0;
$('#drop').bind({
dragenter: function(ev) {
ev.preventDefault(); // needed for IE
counter++;
$(this).addClass('red');
},
dragleave: function() {
counter--;
if (counter === 0) {
$(this).removeClass('red');
}
}
});
참고 : 드롭 이벤트에서 카운터를 0으로 재설정하고 추가 된 클래스를 지우십시오.
답변
하위 요소로 드래그 할 때 드래그 리브가 실행되는 것을 방지 할 수 있습니까?
예.
#drop * {pointer-events: none;}
그 CSS는 Chrome에 충분할 것 같습니다.
Firefox에서 사용하는 동안 #drop에는 직접 텍스트 노드가 없어야합니다 (다른 요소가 “자신에게 맡기는” 이상한 문제가 있음). 한 요소 만 남겨 두는 것이 좋습니다 (예 : # 모든 것을 넣을 수있는 드롭)
다음 은 원래 질문 (깨진) 예제를 해결 하는 jsfiddle 입니다.
또한 @Theodore Brown 예제에서 단순화 된 버전을 만들었 지만이 CSS에만 기반합니다.
모든 브라우저가이 CSS를 구현하지는 않습니다 :
http://caniuse.com/pointer-events
Facebook 소스 코드를 보면이 문제를 pointer-events: none;
여러 번 찾을 수 있지만 우아한 저하 폴 백과 함께 사용됩니다. 최소한 너무 간단하고 많은 환경에서 문제를 해결합니다.
답변
가장 간단한 크로스 브라우저 솔루션은 다음과 같습니다.
jsfiddle <-상자 안의 일부 파일을 드래그 해보십시오
당신은 그런 식으로 할 수 있습니다 :
var dropZone= document.getElementById('box');
var dropMask = document.getElementById('drop-mask');
dropZone.addEventListener('dragover', drag_over, false);
dropMask.addEventListener('dragleave', drag_leave, false);
dropMask.addEventListener('drop', drag_drop, false);
몇 마디로, 드롭 존 내부에 “마스크”를 생성합니다. 너비와 높이가 상속되고 위치 절대 값이며 드래그가 시작될 때만 표시됩니다.
따라서 해당 마스크를 표시 한 후 다른 드래그 앤 드롭 이벤트를 연결하여 트릭을 수행 할 수 있습니다.
떠나거나 떨어 뜨린 후에는 마스크를 다시 숨기면됩니다.
간단하고 합병증이 없습니다.
(Obs .: Greg Pettit 조언-마스크가 테두리를 포함한 전체 상자를 가리켜 야합니다)
답변
이 질문을한지 꽤 시간이 지났고 많은 솔루션 (추악한 해킹 포함)이 제공되었습니다.
나는이 답변 에 대한 답변 덕분에 최근에 겪었던 것과 동일한 문제를 해결할 수 있었고이 페이지를 방문하는 사람에게 도움이 될 것이라고 생각했습니다. 전체 아이디어는 부모 또는 자식 요소 중 하나에서 호출 evenet.target
될 ondrageenter
때 마다을 저장하는 것입니다. 그런 다음 ondragleave
현재 대상 ( event.target
)이에 저장된 객체와 같은지 확인하십시오 ondragenter
.
이 두 가지가 일치하는 유일한 경우는 드래그가 브라우저 창을 떠날 때입니다.
이것이 잘 작동하는 이유는 마우스가 요소를 떠난 후 (예 el1
를 들어) 다른 요소에 들어간 경우 ( el2
먼저 el2.ondragenter
)를 호출 한 다음 el1.ondragleave
입니다. 드래그가 떠날 경우에만 / 브라우저 창을 입력하는 event.target
것 ''
모두 el2.ondragenter
와 el1.ondragleave
.
여기 내 작업 샘플이 있습니다. IE9 +, Chrome, Firefox 및 Safari에서 테스트했습니다.
(function() {
var bodyEl = document.body;
var flupDiv = document.getElementById('file-drop-area');
flupDiv.onclick = function(event){
console.log('HEy! some one clicked me!');
};
var enterTarget = null;
document.ondragenter = function(event) {
console.log('on drag enter: ' + event.target.id);
enterTarget = event.target;
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-drag-on-top';
return false;
};
document.ondragleave = function(event) {
console.log('on drag leave: currentTarget: ' + event.target.id + ', old target: ' + enterTarget.id);
//Only if the two target are equal it means the drag has left the window
if (enterTarget == event.target){
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-no-drag';
}
};
document.ondrop = function(event) {
console.log('on drop: ' + event.target.id);
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-no-drag';
return false;
};
})();
그리고 여기 간단한 HTML 페이지가 있습니다 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Multiple File Uploader</title>
<link rel="stylesheet" href="my.css" />
</head>
<body id="bodyDiv">
<div id="cntnr" class="flup-container">
<div id="file-drop-area" class="flup-no-drag">blah blah</div>
</div>
<script src="my.js"></script>
</body>
</html>
올바른 스타일을 사용하면 파일을 화면으로 드래그 할 때마다 내부 div (# file-drop-area)를 훨씬 더 크게 만들어 사용자가 파일을 적절한 위치에 쉽게 놓을 수 있습니다.
답변
이 문제를 해결하는 “올바른”방법은 드롭 대상의 하위 요소에서 포인터 이벤트를 비활성화하는 것입니다 (@HD의 답변에서와 같이). 이 기술을 보여주는 jsFiddle이 있습니다. 불행히도 IE11 이전의 Internet Explorer 버전에서는 포인터 이벤트를 지원 하지 않기 때문에이 기능이 작동 하지 않습니다 .
다행히, 나는 해결 방법을 마련 할 수 있었다 않는 IE의 이전 버전에서 작업을. 기본적으로 dragleave
하위 요소를 드래그 할 때 발생 하는 이벤트를 식별하고 무시 합니다. 부모 에서 dragenter
이벤트가 발생하기 전에 자식 노드에서 dragleave
이벤트가 시작되므로 드롭 대상에서 “ignore-drag-leave”클래스를 추가하거나 제거하는 각 자식 노드에 별도의 이벤트 리스너를 추가 할 수 있습니다. 그러면 드롭 대상의 dragleave
이벤트 리스너는이 클래스가 존재할 때 발생하는 호출을 무시할 수 있습니다. 여기의 이 해결 방법을 보여 jsFiddle은 . Chrome, Firefox 및 IE8 +에서 테스트되고 작동합니다.
최신 정보:
지원되는 경우 포인터 이벤트가 사용되는 (현재 Chrome, Firefox 및 IE11) 기능 감지를 사용하여 결합 된 솔루션 을 보여주는 jsFiddle을 만들었 으며 포인터 이벤트가 지원되지 않는 경우 브라우저는 하위 노드에 이벤트를 추가하는 것으로 돌아갑니다 (IE8 -10).
답변
문제는 dragleave
마우스가 자식 요소 앞에 갔을 때 이벤트가 시작된다는 것입니다.
e.target
요소가 요소와 같은지 확인하기 위해 다양한 방법을 시도했지만 this
개선 할 수 없었습니다.
이 문제를 해결 한 방식은 약간의 해킹이지만 100 % 작동합니다.
dragleave: function(e) {
// Get the location on screen of the element.
var rect = this.getBoundingClientRect();
// Check the mouseEvent coordinates are outside of the rectangle
if(e.x > rect.left + rect.width || e.x < rect.left
|| e.y > rect.top + rect.height || e.y < rect.top) {
$(this).removeClass('red');
}
}
답변
HTML5를 사용하는 경우 부모의 clientRect를 얻을 수 있습니다.
let rect = document.getElementById("drag").getBoundingClientRect();
그런 다음 parent.dragleave ()에서 :
dragleave(e) {
if(e.clientY < rect.top || e.clientY >= rect.bottom || e.clientX < rect.left || e.clientX >= rect.right) {
//real leave
}
}