IT

자식 요소를 가리킬 때 HTML5 드래그 리브가 시작되었습니다.

lottoking 2020. 3. 28. 10:46
반응형

자식 요소를 가리킬 때 HTML5 드래그 리브가 시작되었습니다.


내가 겪고있는 문제 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에는 직접 텍스트 노드가 없어야합니다 (다른 요소가 "자신에게 맡기는" 이상한 문제가 있음). 한 요소 만 남겨 두는 것이 좋습니다 (예 : 내부에 div 사용) # 모든 것을 넣을 수있는 드롭)

다음원래 질문 (깨진) 예제를 해결 하는 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 조언-마스크가 테두리를 포함한 전체 상자를 가리켜 야합니다)


이 문제를 해결하는 "올바른"방법은 드롭 대상의 하위 요소에서 포인터 이벤트를 비활성화하는 것입니다 (@HD의 답변에서와 같이). 이 기술을 보여주는 jsFiddle이 있습니다. 불행히도 IE11 이전의 Internet Explorer 버전에서는 포인터 이벤트를 지원 하지 않기 때문에이 기능이 작동 하지 않습니다 .

다행히, 나는 해결 방법을 마련 할 수 있었다 않는 IE의 이전 버전에서 작업을. 기본적으로 dragleave하위 요소를 드래그 할 때 발생 하는 이벤트를 식별하고 무시 합니다. 부모 에서 dragenter이벤트가 발생하기 전에 자식 노드에서 dragleave이벤트가 시작되므로 드롭 대상에서 "ignore-drag-leave"클래스를 추가하거나 제거하는 각 자식 노드에 별도의 이벤트 리스너를 추가 할 수 있습니다. 그러면 드롭 대상의 dragleave이벤트 리스너는이 클래스가 존재할 때 발생하는 호출을 무시할 수 있습니다. 여기의 이 해결 방법을 보여 jsFiddle은 . Chrome, Firefox 및 IE8 +에서 테스트되고 작동합니다.

최신 정보:

지원되는 경우 포인터 이벤트가 사용되는 (현재 Chrome, Firefox 및 IE11) 기능 감지를 사용하여 결합 된 솔루션보여주는 jsFiddle을 만들었 으며 포인터 이벤트가 지원되지 않는 경우 브라우저는 하위 노드에 이벤트를 추가하는 것으로 넘어갑니다 (IE8 -10).


이 질문을한지 꽤 시간이 지났고 많은 솔루션 (추악한 해킹 포함)이 제공되었습니다.

나는이 답변 에 대한 답변 덕분에 최근에 겪었던 것과 동일한 문제를 해결할 수 있었고이 페이지를 방문하는 사람에게 도움이 될 것이라고 생각했습니다. 전체 아이디어는 부모 또는 자식 요소 중 하나에서 호출 evenet.targetondrageenter때 마다을 저장하는 것입니다. 그런 다음 ondragleave현재 대상 ( event.target)이에 저장된 객체와 같은지 확인하십시오 ondragenter.

이 두 가지가 일치하는 유일한 경우는 드래그가 브라우저 창을 떠날 때입니다.

이것이 잘 작동하는 이유는 마우스가 요소를 떠난 후 (예 el1를 들어) 다른 요소에 들어간 경우 ( el2먼저 el1.ondragenter)를 호출 한 다음 el2.ondragleave입니다. 드래그가 떠날 경우에만 / 브라우저 창을 입력하는 event.target''모두 el1.ondragenterel2.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)를 훨씬 더 크게 만들어 사용자가 파일을 적절한 위치에 쉽게 놓을 수 있습니다.


문제는 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');
               }
           }

매우 간단한 해결책은 pointer-eventsCSS 속성 을 사용하는 것 입니다. 모든 자식 요소에서 드래그 시작none값을 설정하십시오 . 이러한 요소는 더 이상 마우스 관련 이벤트를 트리거하지 않으므로 마우스를 마우스 위로 가져 가지 않아 부모 에서 드래그 리브트리거하지 않습니다 .

auto드래그를 마칠 때이 속성을 다시 설정하는 것을 잊지 마십시오 .)


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
    }
}

여기는 jsfiddle입니다


jQuery 소스 코드 에서 약간의 영감을 받아 Firefox에서 수정할 수 있습니다 .

dragleave: function(e) {
    var related = e.relatedTarget,
        inside = false;

    if (related !== this) {

        if (related) {
            inside = jQuery.contains(this, related);
        }

        if (!inside) {

            $(this).removeClass('red');
        }
    }

}

불행히도 이벤트에는 relatedTarget존재하지 않기 때문에 Chrome에서 작동하지 않으며 dragleaveFirefox에서 예제가 작동하지 않기 때문에 Chrome에서 작업하고 있다고 가정합니다. 위 코드가 구현 된 버전 이 있습니다.


그리고 여기 Chrome 용 솔루션이 있습니다.

.bind('dragleave', function(event) {
                    var rect = this.getBoundingClientRect();
                    var getXY = function getCursorPosition(event) {
                        var x, y;

                        if (typeof event.clientX === 'undefined') {
                            // try touch screen
                            x = event.pageX + document.documentElement.scrollLeft;
                            y = event.pageY + document.documentElement.scrollTop;
                        } else {
                            x = event.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                            y = event.clientY + document.body.scrollTop + document.documentElement.scrollTop;
                        }

                        return { x: x, y : y };
                    };

                    var e = getXY(event.originalEvent);

                    // Check the mouseEvent coordinates are outside of the rectangle
                    if (e.x > rect.left + rect.width - 1 || e.x < rect.left || e.y > rect.top + rect.height - 1 || e.y < rect.top) {
                        console.log('Drag is really out of area!');
                    }
                })

이벤트가 각 드래그 요소에 개별적으로 연결되어 있다고 가정하면이 매우 간단한 솔루션이 지금까지 효과가 있습니다.

if (evt.currentTarget.contains(evt.relatedTarget)) {
  return;
}

매우 간단한 해결책 :

parent.addEventListener('dragleave', function(evt) {
    if (!parent.contains(evt.relatedTarget)) {
        // Here it is only dragleave on the parent
    }
}

다음은 document.elementFromPoint를 사용하는 다른 솔루션입니다.

 dragleave: function(event) {
   var event = event.originalEvent || event;
   var newElement = document.elementFromPoint(event.pageX, event.pageY);
   if (!this.contains(newElement)) {
     $(this).removeClass('red');
   }
}

이것이 효과가 있기를 바랍니다 . 여기에 바이올린이 있습니다.


간단한 해결책은 pointer-events: none의 트리거를 막기 위해 자식 규칙 CSS 규칙을 추가하는 것 입니다 ondragleave. 예를보십시오 :

function enter(event) {
  document.querySelector('div').style.border = '1px dashed blue';
}

function leave(event) {
  document.querySelector('div').style.border = '';
}
div {
  border: 1px dashed silver;
  padding: 16px;
  margin: 8px;
}

article {
  border: 1px solid silver;
  padding: 8px;
  margin: 8px;
}

p {
  pointer-events: none;
  background: whitesmoke;
}
<article draggable="true">drag me</article>

<div ondragenter="enter(event)" ondragleave="leave(event)">
  drop here
  <p>child not triggering dragleave</p>
</div>


이 정확한 문제를 처리하기 위해 Dragster 라는 작은 라이브러리를 작성 했으며 IE에서 자동으로 수행하지 않는 모든 곳에서 작동합니다 (DOM 이벤트 생성자를 지원하지 않지만 jQuery의 사용자 정의 이벤트를 사용하여 비슷한 것을 작성하는 것은 매우 쉽습니다)


이 크로스 브라우저인지 확실하지 않지만 Chrome에서 테스트했으며 문제를 해결합니다.

전체 페이지에서 파일을 끌어다 놓으려고하지만 하위 요소 위로 드래그하면 드래그 리브가 시작됩니다. 내 수정은 마우스의 x와 y를 보는 것입니다.

페이지가로드 될 때 전체 페이지를 오버레이하는 div가 있습니다.

당신이 문서를 드래그하면 그것을 보여주고 부모를 떨어 뜨릴 때 그것을 처리하고 부모를 떠날 때 x와 y를 확인합니다.

$('#draganddrop-wrapper').hide();

$(document).bind('dragenter', function(event) {
    $('#draganddrop-wrapper').fadeIn(500);
    return false;
});

$("#draganddrop-wrapper").bind('dragover', function(event) {
    return false;
}).bind('dragleave', function(event) {
    if( window.event.pageX == 0 || window.event.pageY == 0 ) {
        $(this).fadeOut(500);
        return false;
    }
}).bind('drop', function(event) {
    handleDrop(event);

    $(this).fadeOut(500);
    return false;
});

나는 같은 문제가 있었고 pk7s 솔루션을 사용하려고했습니다. 그것은 효과가 있었지만 여분의 돔 요소없이 조금 더 나아질 수있었습니다.

기본적으로 아이디어는 동일합니다. 놓기 가능한 영역 위에 보이지 않는 오버레이를 추가하십시오. 여분의 돔 요소없이이 작업을 수행 할 수 있습니다. 다음은 CSS 의사 요소가 등장한 부분입니다.

자바 스크립트

var dragOver = function (e) {
    e.preventDefault();
    this.classList.add('overlay');
};

var dragLeave = function (e) {
    this.classList.remove('overlay');
};


var dragDrop = function (e) {
    this.classList.remove('overlay');
    window.alert('Dropped');
};

var dropArea = document.getElementById('box');

dropArea.addEventListener('dragover', dragOver, false);
dropArea.addEventListener('dragleave', dragLeave, false);
dropArea.addEventListener('drop', dragDrop, false);

CSS

이후 규칙은 놓기 가능한 영역에 대해 완전히 덮힌 오버레이를 만듭니다.

#box.overlay:after {
    content:'';
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    z-index: 1;
}

전체 솔루션은 다음과 같습니다. http://jsfiddle.net/F6GDq/8/

나는 그것이 같은 문제를 가진 사람에게 도움이되기를 바랍니다.


드래그 된 요소가 자식인지 확인한 다음 '끌어 넘기'스타일 클래스를 제거하지 마십시오. 매우 간단하고 나를 위해 작동합니다.

 $yourElement.on('dragleave dragend drop', function(e) {
      if(!$yourElement.has(e.target).length){
           $yourElement.removeClass('is-dragover');
      }
  })

나는 같은 문제에 빠져 들었고 여기에 내 해결책이 있습니다. 크로스 브라우저인지 확실하지 않습니다 (버블 링 순서에 따라 다름)

간단하게 jQuery를 사용하지만 솔루션은 프레임 워크 독립적이어야합니다.

이벤트는 다음과 같이 주어진 방식으로 부모에게 버블 링됩니다.

<div class="parent">Parent <span>Child</span></div>

이벤트를 첨부

el = $('.parent')
setHover = function(){ el.addClass('hovered') }
onEnter  = function(){ setTimeout(setHover, 1) }
onLeave  = function(){ el.removeClass('hovered') } 
$('.parent').bind('dragenter', onEnter).bind('dragleave', onLeave)

그리고 그것은 그것에 관한 것입니다. :) 그것은 부모가 onLeave하기 전에 자식에서 onEnter가 발생하더라도 순서를 반대로 바꾸는 것을 지연시키기 때문에 클래스가 먼저 제거 된 후 1 초 후에 다시 적용됩니다.


조금 더 간단한 대체 작업 솔루션.

//Note: Due to a bug with Chrome the 'dragleave' event is fired when hovering the dropzone, then
//      we must check the mouse coordinates to be sure that the event was fired only when 
//      leaving the window.
//Facts:
//  - [Firefox/IE] e.originalEvent.clientX < 0 when the mouse is outside the window
//  - [Firefox/IE] e.originalEvent.clientY < 0 when the mouse is outside the window
//  - [Chrome/Opera] e.originalEvent.clientX == 0 when the mouse is outside the window
//  - [Chrome/Opera] e.originalEvent.clientY == 0 when the mouse is outside the window
//  - [Opera(12.14)] e.originalEvent.clientX and e.originalEvent.clientY never get
//                   zeroed if the mouse leaves the windows too quickly.
if (e.originalEvent.clientX <= 0 || e.originalEvent.clientY <= 0) {

너무 많은 시간을 보낸 후에 나는 의도 한대로 정확하게 작동하는 제안을 받았습니다. 파일을 드래그 할 때만 큐를 제공하고 문서 드래그, 드래그 리브가 Chrome 브라우저에서 고통스러운 깜박임을 유발했습니다.

이것이 내가 해결 한 방법이며 사용자에게 적절한 신호를줍니다.

$(document).on('dragstart dragenter dragover', function(event) {    
    // Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/
    if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) {
        // Needed to allow effectAllowed, dropEffect to take effect
        event.stopPropagation();
        // Needed to allow effectAllowed, dropEffect to take effect
        event.preventDefault();

        $('.dropzone').addClass('dropzone-hilight').show();     // Hilight the drop zone
        dropZoneVisible= true;

        // http://www.html5rocks.com/en/tutorials/dnd/basics/
        // http://api.jquery.com/category/events/event-object/
        event.originalEvent.dataTransfer.effectAllowed= 'none';
        event.originalEvent.dataTransfer.dropEffect= 'none';

         // .dropzone .message
        if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) {
            event.originalEvent.dataTransfer.effectAllowed= 'copyMove';
            event.originalEvent.dataTransfer.dropEffect= 'move';
        } 
    }
}).on('drop dragleave dragend', function (event) {  
    dropZoneVisible= false;

    clearTimeout(dropZoneTimer);
    dropZoneTimer= setTimeout( function(){
        if( !dropZoneVisible ) {
            $('.dropzone').hide().removeClass('dropzone-hilight'); 
        }
    }, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better
});

드립 드롭 이라는 드래그 앤 드롭 모듈을 작성 하여이 이상한 행동을 해결했습니다. 좋은 저수준 드래그 앤 드롭 모듈을 찾고 있다면 무엇이든 (파일 업로드, 인앱 드래그 앤 드롭, 외부 소스에서 드래그하거나 외부 소스로) 사용할 수있는 기초로 사용할 수 있습니다. 모듈 출력 :

https://github.com/fresheneesz/drip-drop

다음은 드립 드롭에서 수행하려는 작업을 수행하는 방법입니다.

$('#drop').each(function(node) {
  dripDrop.drop(node, {
    enter: function() {
      $(node).addClass('red')  
    },
    leave: function() {
      $(node).removeClass('red')
    }
  })
})
$('#drag').each(function(node) {
  dripDrop.drag(node, {
    start: function(setData) {
      setData("text", "test") // if you're gonna do text, just do 'text' so its compatible with IE's awful and restrictive API
      return "copy"
    },
    leave: function() {
      $(node).removeClass('red')
    }
  })
})

라이브러리 없이이 작업을 수행하기 위해 카운터 기술은 내가 드립 드롭에 사용한 것입니다. 최고 등급의 답변은 첫 번째 드롭을 제외한 모든 항목에서 문제가 발생하는 중요한 단계를 놓칩니다. 올바르게 수행하는 방법은 다음과 같습니다.

var counter = 0;    
$('#drop').bind({
    dragenter: function(ev) {
        ev.preventDefault()
        counter++
        if(counter === 1) {
          $(this).addClass('red')
        }
    },

    dragleave: function() {
        counter--
        if (counter === 0) { 
            $(this).removeClass('red');
        }
    },
    drop: function() {
        counter = 0 // reset because a dragleave won't happen in this case
    }
});

비슷한 문제가 있습니다. Chrome에서 dropzone이 깜박 거리는 자식 요소를 가리킬 때 body의 dragleave 이벤트에서 dropzone을 숨기는 코드가 오염되었습니다.

드롭 존을 숨기지 않고 숨기는 기능을 예약하여이 문제를 해결할 수있었습니다. 그런 다음 다른 끌어 놓기 또는 끌어 놓기가 시작되면 예약 된 함수 호출이 취소됩니다.

body.addEventListener('dragover', function() {
    clearTimeout(body_dragleave_timeout);
    show_dropzone();
}, false);

body.addEventListener('dragleave', function() {
    clearTimeout(body_dragleave_timeout);
    body_dragleave_timeout = setTimeout(show_upload_form, 100);
}, false);

dropzone.addEventListener('dragover', function(event) {
    event.preventDefault();
    dropzone.addClass("hover");
}, false);

dropzone.addEventListener('dragleave', function(event) {
    dropzone.removeClass("hover");
}, false);

마우스 포인터가 대상 컨테이너의 드래그 영역을 벗어나면 " dragleave "이벤트가 발생합니다.

어느 단지 부모가있을 수 있습니다 대부분의 경우에서와 같이 많은 이해 낙하 할 후손이 아니라. event.stopPropogation () 이이 경우를 처리해야 한다고 생각 하지만 트릭을 수행하지 않는 것 같습니다.

위에서 언급 한 일부 솔루션은 대부분의 경우 작동하는 것처럼 보이지만 iframe 과 같은 dragenter / dragleave 이벤트를 지원하지 않는 어린이의 경우 실패합니다 .

1 해결 방법은 event.relatedTarget 을 확인하고 컨테이너 안에 있는지 확인한 다음 여기에서 한 것처럼 dragleave 이벤트 를 무시하는 것입니다.

function isAncestor(node, target) {
    if (node === target) return false;
    while(node.parentNode) {
        if (node.parentNode === target)
            return true;
        node=node.parentNode;
    }
    return false;
}

var container = document.getElementById("dropbox");
container.addEventListener("dragenter", function() {
    container.classList.add("dragging");
});

container.addEventListener("dragleave", function(e) {
    if (!isAncestor(e.relatedTarget, container))
        container.classList.remove("dragging");
});

여기 에서 작동하는 바이올린을 찾을 수 있습니다 !


다음은 이벤트 타이밍을 기반으로하는 다른 접근 방식입니다.

dragenter자식 요소에서 전달 이벤트는 부모 요소에 의해 캡처 될 수 있으며 항상 dragleave. 이 두 이벤트 사이의 타이밍은 실제로 가능한 모든 마우스 동작보다 짧습니다. 따라서 아이디어는 dragenter발생 시간을 기억하고 dragleave이후에 "너무 빠르지 않은"이벤트를 필터링 하는 것입니다.

이 간단한 예제는 Chrome 및 Firefox에서 작동합니다.

var node = document.getElementById('someNodeId'),
    on   = function(elem, evt, fn) { elem.addEventListener(evt, fn, false) },
    time = 0;

on(node, 'dragenter', function(e) {
    e.preventDefault();
    time = (new Date).getTime();
    // Drag start
})

on(node, 'dragleave', function(e) {
    e.preventDefault();
    if ((new Date).getTime() - time > 5) {
         // Drag end
    }
})

pimvdb ..

dragleave 대신 drop 을 사용해보십시오 . 그것은 나를 위해 일했다. 이것이 당신의 문제를 해결하기를 바랍니다.

jsFiddle을 확인하십시오 : http://jsfiddle.net/HU6Mk/118/

$('#drop').bind({
                 dragenter: function() {
                     $(this).addClass('red');
                 },

                 drop: function() {
                     $(this).removeClass('red');
                 }
                });

$('#drag').bind({
                 dragstart: function(e) {
                     e.allowedEffect = "copy";
                     e.setData("text/plain", "test");
                 }
                });

transitioning플래그와 함께 타임 아웃을 사용 하고 맨 위 요소를들을 수 있습니다 . dragenter/ dragleave하위 이벤트에서 컨테이너까지 버블 링됩니다.

때문에 dragenter전에 자식 요소 화재에 dragleave컨테이너의, 우리는이 1ms에 대한 전환으로 플래그 쇼를 설정합니다 ... dragleave이 1ms 전에 플래그를 확인합니다 리스너는 최대입니다.

플래그는 자식 요소로 전환하는 동안에 만 참이되고 (컨테이너의) 부모 요소로 전환 할 때 참이되지 않습니다.

var $el = $('#drop-container'),
    transitioning = false;

$el.on('dragenter', function(e) {

  // temporarily set the transitioning flag for 1 ms
  transitioning = true;
  setTimeout(function() {
    transitioning = false;
  }, 1);

  $el.toggleClass('dragging', true);

  e.preventDefault();
  e.stopPropagation();
});

// dragleave fires immediately after dragenter, before 1ms timeout
$el.on('dragleave', function(e) {

  // check for transitioning flag to determine if were transitioning to a child element
  // if not transitioning, we are leaving the container element
  if (transitioning === false) {
    $el.toggleClass('dragging', false);
  }

  e.preventDefault();
  e.stopPropagation();
});

// to allow drop event listener to work
$el.on('dragover', function(e) {
  e.preventDefault();
  e.stopPropagation();
});

$el.on('drop', function(e) {
  alert("drop!");
});

jsfiddle : http://jsfiddle.net/ilovett/U7mJj/


드래그 대상의 모든 자식 객체에 대한 포인터 이벤트를 제거해야합니다.

function disableChildPointerEvents(targetObj) {
        var cList = parentObj.childNodes
        for (i = 0; i < cList.length; ++i) {
            try{
                cList[i].style.pointerEvents = 'none'
                if (cList[i].hasChildNodes()) disableChildPointerEvents(cList[i])
            } catch (err) {
                //
            }
        }
    }

이 코드를 사용하십시오 http://jsfiddle.net/HU6Mk/258/ :

$('#drop').bind({
         dragenter: function() {
             $(this).addClass('red');
         },

         dragleave: function(event) {
             var x = event.clientX, y = event.clientY,
                 elementMouseIsOver = document.elementFromPoint(x, y);
             if(!$(elementMouseIsOver).closest('.red').length) {
                 $(this).removeClass('red');
             }
        }
    });

event.eventPhase를 사용하십시오. 대상을 입력하지 않은 경우에만 2 (Event.AT_TARGET)로 설정되고, 그렇지 않으면 3 (Event.BUBBLING_PHASE)으로 설정됩니다.

dragPave 이벤트를 바인딩하거나 바인딩 해제하기 위해 eventPhase를 사용했습니다.

$('.dropzone').on('dragenter', function(e) {

  if(e.eventPhase === Event.AT_TARGET) {

    $('.dropzone').addClass('drag-over');

    $('.dropzone').on('dragleave', function(e) {
      $('.dropzone').removeClass('drag-over');
    });

  }else{

    $('.dropzone').off('dragleave');

  }
})

귀도

참고 URL : https://stackoverflow.com/questions/7110353/html5-dragleave-fired-when-hovering-a-child-element

반응형