자식 요소 위로 드래그하면 부모 요소의 'dragleave'가 발생합니다.


163

개요

다음 HTML 구조 를 가지고 있으며 요소에 dragenterand dragleave이벤트를 첨부했습니다 <div id="dropzone">.

<div id="dropzone">
    <div id="dropzone-content">
        <div id="drag-n-drop">
            <div class="text">this is some text</div>
            <div class="text">this is a container with text and images</div>
        </div>
    </div>
</div>

문제

나는 통해 파일을 드래그 할 때 <div id="dropzone">dragenter예상대로 이벤트가 발생합니다. 그러나와 같은 자식 요소 위로 마우스를 움직이면 요소 <div id="drag-n-drop">에 대해 dragenter이벤트가 시작된 <div id="drag-n-drop">다음 요소에 대해 dragleave이벤트가 시작 <div id="dropzone">됩니다.

<div id="dropzone">요소 위로 다시 마우스를 가져 가면 dragenter이벤트가 다시 시작되고 멋지지만 dragleave방금 떠난 하위 요소에 대해 이벤트가 시작되므로 removeClass명령이 실행되지만 멋지지 않습니다.

이 동작은 두 가지 이유로 문제가 있습니다.

  1. 나는 dragenter& dragleave에 첨부 <div id="dropzone">하기 때문에 어린이 요소에 왜 이러한 이벤트가 첨부되어 있는지 이해할 수 없습니다.

  2. 나는 <div id="dropzone">아이들을 가리킬 때 여전히 요소를 드래그 하고 dragleave있으므로 발사 하고 싶지 않습니다 !

jsFiddle

http://jsfiddle.net/yYF3S/2/ 와 함께 땜질하는 jsFiddle은 다음과 같습니다.

질문

따라서 ... <div id="dropzone">요소 위로 파일을 드래그 할 때 dragleave하위 요소를 드래그하더라도 실행되지 않도록하려면 어떻게해야합니까? <div id="dropzone">요소를 떠날 때만 실행되어야합니다 . 요소의 경계 내에서 마우스를 움직이거나 끌어다 놓으면 이벤트가 트리거 되지 않아야 합니다 dragleave.

적어도 HTML5 드래그 앤 드롭을 지원하는 브라우저에서 브라우저 간 호환이 가능해야 하므로이 답변 은 적합하지 않습니다.

Google과 Dropbox가 이것을 알아 낸 것처럼 보이지만 소스 코드가 축소 / 복잡해 구현에서이를 파악할 수 없었습니다.


를 통한 이벤트 전파 방지e.stopPropagation();
Blender

나는 이미 내가 생각합니다 ... 업데이트 확인
Hristo

jsfiddle.net 어딘가에 데모를 게시 할 수 있습니까 ?
Blender

@Blender ... 물론, 몇 분만 기다려주세요!
Hristo

@Blender ... 나는 바이올린으로 내 질문을 업데이트했습니다
Hristo

답변:


171

자식 요소에 이벤트를 바인딩 할 필요가 없으면 항상 pointer-events 속성을 사용할 수 있습니다.

.child-elements {
  pointer-events: none;
}

4
최고의 솔루션! CSS를 사용하여 문제를 해결할 수 있다고 생각조차하지 못했습니다. 대단히 감사합니다!
serg66

1
오 예. 이거 야!
mcmlxxxiii

23
이 접근법의 유일한 단점은 자식 요소에서 모든 포인터 이벤트를 처리한다는 것입니다 (예 : 더 이상 별도의 요소를 가질 수 없음) :hover 스타일을 갖거나 이벤트 처리기를 클릭 ). 이러한 이벤트를 유지하려면 다음과 같은 다른 해결 방법을 사용하십시오. bensmithett.github.io/dragster
Ben

2
css child selector와 결합하여 dropzone의 모든 자녀에게 도달하십시오. .dropzone * {pointer-events: none;}
Philipp F

7
이미 jQuery를 사용하고 있으므로 $('.element').addClass('dragging-over')드래그하는 요소와 $('.element').removeClass('dragging-over')드래그 할 때만 사용할 수 있습니다. 그런 다음 CSS에서 사용할 수 있습니다 .element.dragging-over * { pointer-events: none; }. 드래그 할 때만 모든 자식 요소에서 포인터 이벤트가 제거됩니다.
Gavin

56

나는 마침내 내가 만족하는 해결책을 찾았다. 실제로 원하는 것을 수행하는 여러 가지 방법을 찾았지만 현재 솔루션만큼 성공하지 못했습니다 ... 한 솔루션에서 테두리를 추가 / 제거 한 결과 잦은 깜박임이 발생했습니다.#dropzone 요소에 ... 다른 테두리 브라우저에서 마우스를 가져 가면 제거되지 않았습니다.

어쨌든, 가장 좋은 해키 솔루션은 다음과 같습니다.

var dragging = 0;

attachEvent(window, 'dragenter', function(event) {

    dragging++;
    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragover', function(event) {

    $(dropzone).addClass('drag-n-drop-hover');

    event.stopPropagation();
    event.preventDefault();
    return false;
});

attachEvent(window, 'dragleave', function(event) {

    dragging--;
    if (dragging === 0) {
        $(dropzone).removeClass('drag-n-drop-hover');
    }

    event.stopPropagation();
    event.preventDefault();
    return false;
});

이것은 잘 작동하지만 Firefox가 이중 호출이기 때문에 Firefox에서 문제가 발생했습니다. dragenter 되어 카운터가 꺼져 했습니다. 그러나 그럼에도 불구하고 매우 우아한 해결책은 아닙니다.

그런 다음이 질문을 우연히 발견했습니다 : 창 밖으로 드래그 할 때 Firefox에서 dragleave 이벤트를 감지하는 방법

그래서 나는 대답을 받아 내 상황에 적용했습니다.

$.fn.dndhover = function(options) {

    return this.each(function() {

        var self = $(this);
        var collection = $();

        self.on('dragenter', function(event) {
            if (collection.size() === 0) {
                self.trigger('dndHoverStart');
            }
            collection = collection.add(event.target);
        });

        self.on('dragleave', function(event) {
            /*
             * Firefox 3.6 fires the dragleave event on the previous element
             * before firing dragenter on the next one so we introduce a delay
             */
            setTimeout(function() {
                collection = collection.not(event.target);
                if (collection.size() === 0) {
                    self.trigger('dndHoverEnd');
                }
            }, 1);
        });
    });
};

$('#dropzone').dndhover().on({
    'dndHoverStart': function(event) {

        $('#dropzone').addClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    },
    'dndHoverEnd': function(event) {

        $('#dropzone').removeClass('drag-n-drop-hover');

        event.stopPropagation();
        event.preventDefault();
        return false;
    }
});

이것은 깨끗하고 우아하며 지금까지 테스트 한 모든 브라우저에서 작동하는 것 같습니다 (IE는 아직 테스트하지 않았습니다).


이것은 지금까지 가장 좋은 해결책입니다. 유일한 문제는 파일을 추가하고 제거하고 다른 파일을 드래그 할 때이 코드가 작동하지 않는다는 것입니다. HoverEnd를 올리고 HoverStart를 다시 올린 후에 만이 코드가 다시 작동합니다.
MysticEarth

@MysticEarth 작동하지 않을 때 데모하기 위해 jsFiddle을 함께 사용할 수 있습니까?
Hristo

1
답변 주셔서 감사합니다. HTML5 드래그 앤 드롭 인터페이스와 이벤트 리스너가 정말 고통 스러울 수 있기 때문에 이것은 정말 도움이되었습니다. 이는 특히 드롭 존 요소의 여러 인스턴스를 처리하려는 경우 미친 이벤트를 처리하는 가장 좋은 방법입니다.
Nico O

왜 stopPropagation () preventDefault ()를 호출하고 false를 반환해야합니까? false를 반환하면 충분합니다. 해야합니까?
Dejo

그것은 중복이지만, 호출 stopPropagation()preventDefault()바람직하다. 을 삭제합니다 return false.
Peeja

38

이것은 조금 못 생겼지 만 젠장 작동합니다! ...

'dragenter'처리기에서 event.target (클로저 내부의 변수 등)을 저장 한 다음 'dragleave'처리기에서 event.target === 저장 한 코드 만 실행하십시오.

원하지 않는 경우 (예 : 자식 요소를 떠난 후 입력 할 때) '급격한'발화가 발생하면 마우스가 부모를 떠나기 전에 마지막으로 발사 될 때 부모가 항상 부모에 있습니다. 의도 된 'dragleave'앞의 마지막 'dragenter'.

(function () {

    var droppable = $('#droppable'),
        lastenter;

    droppable.on("dragenter", function (event) {
        lastenter = event.target;
        droppable.addClass("drag-over");            
    });

    droppable.on("dragleave", function (event) {
        if (lastenter === event.target) {
            droppable.removeClass("drag-over");
        }
    });

}());

나중에 다시 시도하겠습니다. 어쨌든 내 솔루션보다 깨끗 해 보이지만 브라우저를 통해 브라우저 간 호환성이 확실하지 않습니다. 이것을 어디서 테스트 했습니까?
Hristo

1
Chrome 만 사용하며 하위 요소와 컨테이너 사이에 물리적 간격이 있다고 가정 할 때만 작동 할 수 있습니다.
hacklikecrack

5
내가 가장 좋아하는 답변은 여기입니다. 전혀 못 생겼다 :)
Matt Way

1
IE, Chrome, FF에서 나를 위해
일함

1
자식에서 드래그가 시작되면 작동하지 않습니다. 예를 들어, 자식 내부에서 드래그가 시작되는 방식으로 다른 창에서 무언가를 드래그합니다.
FINDarkside

29

처음에는 pointer-events: none접근 방식을 포기하는 사람들과 동의했습니다 . 그러나 나는 나 자신에게 물었다 :

드래그가 진행되는 동안 자식 요소에서 작동하려면 포인터 이벤트가 정말로 필요 합니까?

내 경우에는, 내가 물건의 많은 등, 인라인 편집 추가 작업을위한 버튼을 표시 예를 들어, 가져가, 아이들에 어떤 일이 일어나고있다 ... 그러나 아무도 그 필요하거나 원하는 사실에없는 동안 드래그.

필자의 경우 다음과 같이 부모 컨테이너의 모든 자식 노드에 대해 포인터 이벤트를 선택적으로 해제합니다.

  div.drag-target-parent-container.dragging-in-progress * {
    pointer-events: none;
  }

내가 좋아하는 접근 방식을 사용하여 / 이벤트 핸들러 dragging-in-progress에서 클래스를 추가 / 제거하십시오 . 알.dragEnterdragLeavedragStart


1
이 솔루션은 가장 간단하고 완벽합니다. dragstart이벤트에 클래스를 추가하고에서 제거하십시오 dragend.
cmann

이것은 꽤 좋은 해결책이지만 완벽하지는 않습니다. 다른 창에서 드래그하여 자식 요소에서 드래그가 시작되면 dragEnter는 실행되지 않습니다. 자식으로 이동할 때 dragEnter가 실행되지 않을 정도로 마우스를 빠르게 이동할 수도 있지만 100 % 확실하지는 않습니다.
FINDarkside

12

이것은 Chrome 버그 인 것 같습니다.

내가 생각할 수있는 유일한 해결 방법은 이벤트를 캡처하기 위해 투명한 오버레이 요소를 만드는 것입니다 : http://jsfiddle.net/yYF3S/10/

JS :

$(document).ready(function() {
    var dropzone = $('#overlay');

    dropzone.on('dragenter', function(event) {
        $('#dropzone-highlight').addClass('dnd-hover');
    });

    dropzone.on('dragleave', function(event) {
        $('#dropzone-highlight').removeClass('dnd-hover');
    });

});​

HTML :

<div id="dropzone-highlight">
    <div id="overlay"></div>

    <div id="dropzone" class="zone">
        <div id="drag-n-drop">
            <div class="text1">this is some text</div>
            <div class="text2">this is a container with text and images</div>
        </div>
    </div>
</div>

<h2 draggable="true">Drag me</h2>

답변 주셔서 감사합니다, 블렌더. 나는 이미 이것을 시도했다. 이 솔루션의 문제점은 오버레이 요소가 하위 요소를 "오버레이"하여 상호 작용해야한다는 것입니다. 오버레이를 사용하면 하위 요소와의 상호 작용을 비활성화 할 수 있습니다. -드롭 상자 ... 드래그 앤 드롭하거나 입력 요소를 클릭하여 파일을 선택할 수 있습니다.
Hristo

다음은 귀하의 솔루션이 만족하지 않는 바이올린의 예입니다 ... jsfiddle.net/UnsungHero97/yYF3S/11
Hristo

혼란 스러워요. 하위 요소와 상호 작용해야하는 이유는 무엇입니까?
Blender

필자의 경우 "dropzone"의 하위 요소는 파일 선택 버튼입니다. 따라서 파일을 끌어서 놓지 않으려면 입력 요소를 사용하여 파일을 선택할 수 있습니다. 그러나 오버레이를 사용하면 입력 요소를 클릭 할 수 없습니다. 말이 되나요?
Hristo

@Blender 대부분의 경우 페이지의 요소가 아닌 데스크탑에서 파일을 드래그해야하므로 작동하지 않습니다.
Mārtiņš Briedis

5

문제는 드롭 존 내부의 요소는 물론 드롭 존의 일부이며 자식을 입력하면 부모를 떠나는 것입니다. 이것을 해결하는 것은 쉽지 않습니다. 자녀에게 이벤트를 추가해도 부모에게 클래스를 다시 추가 할 수 있습니다.

$("#dropzone,#dropzone *").on('dragenter', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

이벤트는 여전히 여러 번 발생하지만 아무도 볼 수 없습니다.

// 편집 : dragmove 이벤트를 사용하여 dragleave 이벤트를 영구적으로 덮어 씁니다.

$("#dropzone,#dropzone *").on('dragenter dragover', function(event) {

    // add a class to #dropzone

    event.stopPropagation(); // might not be necessary
    event.preventDefault();
    return false;
});

dropzone에 대해서만 dragleave 이벤트를 정의하십시오.


2
그래도 문제는 해결되지 않습니다. 진짜 문제는 dragleave... 내가 아이를 떠날 때, 나는 여전히 부모 안에있을 수 #dropzone있지만 그 dragenter사건은 다시 발생하지 않습니다 :(
Hristo

dragenter가 다시 시작되지 않습니까?
Oliver

아 맞아 ... 다시 해고됐지만 해고 된 직후 dragleave에 자식 요소에 대한 이벤트가 해고되었으므로 removeClass명령이 다시 실행 됨
Hristo

나는 dragleave오직 #dropzone...에 대해서만 정의 할 수는 없다면,이 문제는 없을 것입니다.
Hristo

아니요, 어린이들에게 드래그 리브 이벤트를 추가하지 않았습니다.
Oliver

4

으로 benr는 언급 이 답변 , 당신은 이벤트에 대한 화재에 자식 노드를 방지 할 수 있지만, 당신은 몇 가지 이벤트를 바인딩해야하는 경우,이 작업을 수행 :

#dropzone.dragover *{
   pointer-events: none;
}

그리고 이것을 JS 코드에 추가하십시오 :

$("#dropzone").on("dragover", function (event) {
   $("#dropzone").addClass("dragover");
});

$("#dropzone").on("dragleave", function (event) {
   $("#dropzone").removeClass("dragover");
});

2
나를 위해 오버레이가 지속적으로 깜박입니다.
Andrey Mikhaylov-lolmaus

3

jQuery를 사용하는 경우 https://github.com/dancork/jquery.event.dragout을 확인 하십시오.

정말 굉장합니다.

진정한 드래그 리브 기능을 처리하기 위해 만들어진 특별 이벤트.

HTML5 드래그 리브 이벤트는 마우스 아웃과 유사하게 작동합니다. 이 플러그인은 드래그하는 동안 mouseleave 스타일 기능을 복제하기 위해 만들어졌습니다.

사용 예 :

$ ( '# myelement'). on ( 'dragout', function (event) {// 당신의 코드});

편집 : 실제로 jQuery에 의존하지 않는다고 생각합니다. 아직 코드 없이도 코드를 사용할 수 있습니다.


와! 드래그 아웃은 부모 드롭 존을 떠나지 않았지만 많은 하위 요소가 발생하여 레이아웃에서 작동 한 것입니다 dragleave.
Mark Kasson

지난 한 시간 동안이 문제와 싸우고 나면 dragout나에게 유일한 해결책이었습니다.
Jason Hazel

2

@ hristo 나는 훨씬 더 우아한 솔루션을 가지고 있습니다. 그것이 사용할 수 있는지 확인하십시오.

당신의 노력은 결국 낭비되지 않았습니다. 처음에는 귀하의 것을 사용했지만 FF, 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
});

당신은 범위 변수의 일부 아웃 정의를 누락하는 것, 나는 가정var dropZoneHideDelay=70, dropZoneVisible=true;
티모 Huovinen

@TimoHuovinen 예, 맞습니다. 구현시 dropZoneHideDelay, dropZoneVisible두 가지 'on'문서 이벤트에 모두 필요합니다 .
visitsb

2

내 두 센트 : 드롭 존 위에 레이어를 숨긴 다음 드래그 할 때 표시하고 드래그 리브를 대상으로합니다.

데모 : https://jsfiddle.net/t6q4shat/

HTML

<div class="drop-zone">
  <h2 class="drop-here">Drop here</h2>
  <h2 class="drop-now">Drop now!</h2>
  <p>Or <a href="#">browse a file</a></p>
  <div class="drop-layer"></div>
</div>

CSS

.drop-zone{
  padding:50px;
  border:2px dashed #999;
  text-align:center;
  position:relative;
}
.drop-layer{
  display:none;
  position:absolute;
  top:0;
  left:0;
  bottom:0;
  right:0;
  z-index:5;
}
.drop-now{
  display:none;
}

JS

$('.drop-zone').on('dragenter', function(e){
    $('.drop-here').css('display','none');
    $('.drop-now').css('display','block');
    $(this).find('.drop-layer').css('display','block');
    return false;
});

$('.drop-layer').on('dragleave', function(e){
    $('.drop-here').css('display','block');
    $('.drop-now').css('display','none');
    $(this).css('display','none');
    return false;
});

간단하고 효과적입니다! 나는 stopPropagation () 경로를 따라 가고 있었고 모든 어린이에게 이벤트 핸들러를 적용하는 것을 좋아하지 않았습니다. 혼란스러워 보였지만 이것은 잘 작동하고 구현하기 간단합니다. 좋은 생각.
Jon Catmull

1

그래서 나를 위해 접근 방식 pointer-events: none;이 너무 잘 작동하지 않았습니다 ... 그래서 여기 내 대안 솔루션이 있습니다.

    #dropzone {
        position: relative;
    }

    #dropzone(.active)::after {
        position: absolute;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0;
        content: '';
    }

이런 식으로 dragleave부모 (자식) 나 dragover자식 요소 는 불가능합니다 . 도움이 되었기를 바랍니다 :)

* dragenter또는 때 '.active'클래스를 추가 dragleave합니다. 그러나 당신이 그것없이 일하고 있다면 그냥 수업을 떠나십시오.


1
나는 이것을 EmberJS D & D 컴포넌트에서 시도했고 프로그래밍 방식으로 'active'클래스를 추가하는 것은 마우스가 부모 div (ember-view)에 들어가는 시간의 약 40 %가 너무 느립니다. 이유가 확실하지 않습니다. 그러나 그 상태를 유지하고 훌륭하게 작동 하므로이 간단한 솔루션에 감사드립니다. Safari, Chrome, Firefox의 최신 버전 (현재)의 Mac에서 테스트되었습니다.
rmcsharry

1

광범위하게 테스트되지는 않았지만 현재 Chrome에서 작동합니다.

Coffeescript를 실례합니다.

  dragEndTimer = no

  document.addEventListener 'dragover', (event) ->
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'
    event.preventDefault()
    return no

  document.addEventListener 'dragenter', (event) ->
    $('section').scrollTop(0)
    clearTimeout dragEndTimer
    $('body').addClass 'dragging'

  document.addEventListener 'dragleave', (event) ->
    dragEndTimer = setTimeout ->
      $('body').removeClass 'dragging'
    , 50

이로 인해 Chrome 깜박임 버그 또는 적어도 문제를 일으킨 버그가 수정되었습니다.



1

내 버전 :

$(".dropzone").bind("dragover", function(e){
    console.log('dragover');
});

$(".dropzone").bind("dragleave", function(e) {
  var stopDrag = false;
  if (!e.relatedTarget) stopDrag = true;
  else {
    var parentDrop = $(e.relatedTarget).parents('.dropzone');
    if (e.relatedTarget != this && !parentDrop.length) stopDrag = true;
  }

  if (stopDrag) {
    console.log('dragleave');
  }
});

이 레이아웃으로 :

<div class="dropzone">
  <div class="inner-zone">Inner-zone</div>
</div>

나는 위해 요소 클래스의 덤프를했습니다 e.target, e.currentTarget, e.relatedTarget모두 dragoverdragleave 이벤트.

부모 블록 ( .dropzone) 을 떠나는 것이이 블록 e.relatedTarget의 자식이 아니므로 드롭 영역을 벗어났습니다.


0

여기, 가장 간단한 해결책 중 하나 ● ︿ ●

바이올린을 보세요 <-상자 안의 파일을 드래그 해보세요

다음과 같이 할 수 있습니다 :

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);

이를 통해 이미 무슨 일이 일어나고 있는지 알아야합니다.
바이올린 만 살펴보세요.


0

비슷한 문제가 있었고이 방법으로 수정했습니다.

문제 : 사용자가 "드롭 영역"(ul 요소)에 요소를 놓을 때 기능 drop (ev)이 발생하지만 불행히도 요소가 하위 요소 중 하나 (li 요소)에 놓일 때 발생합니다.

수정 :

function drop(ev) { 
ev.preventDefault(); 
data=ev.dataTransfer.getData('Text'); 
if(ev.target=="[object HTMLLIElement]")  
{ev.target.parentNode.appendChild(document.getElementById(data));}
else{ev.target.appendChild(document.getElementById(data));} 
} 

0

사용자가 파일을 공간으로 드래그 할 때 상자 색상이 변경되는 파일 업로드 상자에 대해 직접 구현하려고했습니다.

Javascript와 CSS가 잘 혼합 된 솔루션을 찾았습니다. divid 가있는 놓기 가능한 영역이 있다고 가정하십시오 #drop. 이것을 자바 스크립트에 추가하십시오 :

$('#drop').on('dragenter', function() {
    $(this).addClass('dragover');
    $(this).children().addClass('inactive');
});

$('#drop').on('dragleave', function() {
    $(this).removeClass('dragover');
    $(this).children().removeClass('inactive');
});

그런 다음 이것을 CSS에 추가하여 모든 어린이가 수업을 비활성화하십시오 .inactive.

#drop *.inactive {
    pointer-events: none;
}

따라서 사용자가 요소를 상자 위로 드래그하는 동안 하위 요소는 비활성화됩니다.


0

자식 요소에 대한 통제력을 잃고 싶지 않기 때문에 여기에 제시된 해결 방법 중 어느 것에도 만족하지 못했습니다.

그래서 다른 로직 접근법을 사용하여 jquery-draghandler 라는 jQuery 플러그인으로 변환했습니다 . DOM을 조작하지 않으므로 고성능을 보장합니다. 사용법은 간단합니다.

$(document).ready(function() {

    $(selector).draghandler({
        onDragEnter: function() {
            // $(this).doSomething();
        },
        onDragLeave: function() {
            // $(this).doSomethingElse();
        }
    });

});

DOM 기능을 손상시키지 않고 문제를 완벽하게 처리합니다.

Git 저장소 에서 다운로드, 세부 사항 및 설명 .


플러그인에서 드래그 입력 이벤트를 받으려면 어떻게해야합니까?
Woody

실제로 지시문을 테스트하지는 않았지만 부모 요소 (A)가 실제로 확인하려는 요소 (B)를 둘러싸 지 않으면 작동하지 않는다고 생각합니다. 예를 들어 B의 아래쪽 가장자리와 A의 아래쪽 가장자리 사이에 패딩이 없으면 요소 A에 대해 dragenter가 실행되지 않습니다.
marcelj 2016 년

@marcelj 요소 A 는 본문 문서 자체가 될 수 있으므로 최소한의 패딩으로 주변 요소 (본문이 작업을 수행)가 필요하지 않습니다. 이 접근법에서 나중에 찾은 한계는 frames로 작업하고 요소가 경계에 있다는 것입니다. 이 경우이 접근법을 제안하지 않습니다.
Luca Fagioli 16:14에

0

나는 실제로 내가보고있는 것을 좋아한다 https://github.com/lolmaus/jquery.dragbetter/그러나 가능한 대안을 공유하고 싶었습니다. 내 일반적인 전략은 배경이나 스타일을 자식으로 드래그 할 때 배경 스타일을 자식이 아닌 드롭 영역에 적용하는 것입니다. 그런 다음 놓기 영역을 끌 때 스타일을 제거합니다. 아이를 옮길 때 아이디어는 드롭 존에서 스타일을 제거하더라도 (드래그 리브 발생) 아이를 드래그 할 때 부모 드롭 존에 스타일을 다시 적용하는 것입니다. 문제는 dropzone에서 dropzone의 자식으로 이동할 때 dragleave 전에 자식에서 dragenter가 시작되어 내 스타일이 잘못 적용되는 것입니다. 나를위한 해결책은 타이머를 사용하여 dragenter 이벤트를 메시지 큐로 되돌려 놓아 드래그 리브 후에 처리 할 수있었습니다. 타이머 콜백에서 이벤트에 액세스하기 위해 클로저를 사용했습니다.

$('.dropzone').on('dragenter', function(event) {
  (function (event) {
    setTimeout(function () {
      $(event.target).closest('.dropzone').addClass('highlight');
    }, 0);
  }) (event.originalEvent); 
});

이것은 크롬, 즉 파이어 폭스에서 작동하는 것으로 보이고 dropzone의 어린이 수에 관계없이 작동합니다. 이벤트 재 시퀀싱을 보장하는 시간 초과에 대해 약간 불안하지만, 내 사용 사례에는 잘 작동하는 것 같습니다.


0

나는 이것을 직접 구현하려고했지만 Jquery 나 플러그인을 원하지 않았다.

나에게 가장 적합한 방법으로 파일 업로드를 처리하고 싶었습니다.

파일 구조 :

--- / uploads {업로드 디렉토리}

--- /js/slyupload.js {javascript 파일.}

--- index.php

--- upload.php

--- styles.css {작은 스타일링 ..}

HTML 코드 :

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>my Dzone Upload...</title>
<link rel="stylesheet" href="styles.css" />
</head>

<body>
    <div id="uploads"></div>        
    <div class="dropzone" id="dropzone">Drop files here to upload</div>     
    <script type="text/javascript" src="js/slyupload.js"></script>      
</body>
</html>

그런 다음 첨부 된 자바 스크립트 파일입니다 : 'js / slyupload.js'

<!-- begin snippet:  -->

<!-- language: lang-js -->

    // JavaScript Document

    //ondragover, ondragleave...


    (function(){        

        var dropzone = document.getElementById('dropzone');
        var intv;

        function displayUploads(data){
            //console.log(data, data.length);
            var uploads = document.getElementById('uploads'),anchor,x;

            for(x=0; x < data.length; x++){

                //alert(data[x].file);
                anchor = document.createElement('a');
                anchor.href = data[x].file;
                anchor.innerText = data[x].name;

                uploads.appendChild(anchor);
            }               
        }

        function upload(files){
            //console.log(files);
            var formData = new FormData(), 
                xhr      = new XMLHttpRequest(),    //for ajax calls...
                x;                                  //for the loop..

                for(x=0;x<files.length; x++){
                    formData.append('file[]', files[x]);

                    /*//do this for every file...
                    xhr = new XMLHttpRequest();

                    //open... and send individually..
                    xhr.open('post', 'upload.php');
                    xhr.send(formData);*/
                }

                xhr.onload = function(){
                    var data = JSON.parse(this.responseText);   //whatever comes from our php..
                    //console.log(data);
                    displayUploads(data);

                    //clear the interval when upload completes... 
                    clearInterval(intv);
                }                   

                xhr.onerror = function(){
                    console.log(xhr.status);
                }

                //use this to send all together.. and disable the xhr sending above...

                //open... and send individually..
                intv = setInterval(updateProgress, 50);
                xhr.open('post', 'upload.php');
                xhr.send(formData);

                //update progress... 
                 /* */                   
        }

        function updateProgress(){
            console.log('hello');
         }          

        dropzone.ondrop = function(e){
            e.preventDefault(); //prevent the default behaviour.. of displaying images when dropped...
            this.className = 'dropzone';
            //we can now call the uploading... 
            upload(e.dataTransfer.files); //the event has a data transfer object...
        }

        dropzone.ondragover = function(){
            //console.log('hello');
            this.className = 'dropzone dragover';
            return false;
        }

        dropzone.ondragleave = function(){
            this.className = 'dropzone';
            return false;
        }           
    }(window));

CSS :

body{
	font-family:Arial, Helvetica, sans-serif; 
	font-size:12px;
}

.dropzone{
	width:300px; 
	height:300px;
	border:2px dashed #ccc;
	color:#ccc;
	line-height:300px;
	text-align:center;
}

.dropzone.dragover{
	border-color:#000;
	color:#000;
}


0

미안하지만 jquery가 아닌 자바 스크립트이지만, 나를 위해 가장 논리적 인 방법입니다. 브라우저는 dropenter 전에 (이전 요소의) dropleave를 호출해야합니다 (새로운 요소의 경우 가장 먼저 물건을 떠나기 전에 다른 것을 입력 할 수 없기 때문에 왜 그런지 이해하지 못합니다!) 드랍 리브는 이렇게 :

function mydropleave(e)
{
    e.preventDefault();
    e.stopPropagation();

    setTimeout(function(e){ //the things you want to do },1);
}

dropdroper는 dropleave 후에 일어날 것입니다.


-1

greedy : true의 함수로 자식을 사용하십시오 droppable. 그런 다음 첫 번째 레이어에서 클릭 한 이벤트 만 시작하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.