IT TIP

dragenter 및 dragover 이벤트에서 드래그되는 항목 확인

itqueen 2020. 11. 24. 20:43
반응형

dragenter 및 dragover 이벤트에서 드래그되는 항목 확인


HTML5 드래그 가능 API를 사용하려고합니다 ( 문제가 있음을 알고 있지만 ). 지금까지 내가 만난 유일한 눈에 띄는 것은 dragover또는 dragenter이벤트가 발생할 때 드래그되는 항목을 판별하는 방법을 알아낼 수 없다는 것입니다 .

el.addEventListener('dragenter', function(e) {
  // what is the draggable element?
});

나는 그것이 dragstart이벤트 를 발생시키는 마지막 요소라고 가정 할 수 있다는 것을 알고 있지만 .. 멀티 터치. 또한 e.dataTransfer.setDatafrom dragstart을 사용하여 고유 식별자를 첨부 하려고 시도 했지만 분명히 해당 데이터는 / 에서 액세스 할 수 없습니다 .dragoverdragenter

이 데이터는 드롭 이벤트 중에 드롭이 발생한 경우에만 사용할 수 있습니다.

그래서, 어떤 아이디어?

업데이트 : 이 글을 쓰는 시점에서 HTML5 드래그 앤 드롭은 주요 모바일 브라우저에서 구현되지 않는 것으로 보이며 실제로 멀티 터치 모의에 대한 요점을 만듭니다. 그러나 여러 요소가 동시에 드래그되는 것을 막지 않는 것으로 보이는 spec 구현에서 작동하는 솔루션을 원합니다 .

아래에 작동하는 솔루션을 게시 했지만 추악한 해킹입니다. 나는 여전히 더 나은 답변을 기대하고 있습니다.


여기에 아주 명확한 답을 추가하여 여기를 지나가는 모든 사람들에게 분명해졌습니다. 다른 답변에서 여러 번 언급되었지만 여기에 내가 할 수있는 한 분명합니다.

dragover 드래그 이벤트에서 데이터를 볼 수있는 권한이 없습니다.

이 정보는 DRAG_START 및 DRAG_END (드롭) 중에 만 사용할 수 있습니다.

문제는 여기와 같은 사양이나 장소에 대해 충분히 깊이 읽을 때까지 전혀 분명하지 않고 미친 듯하지 않습니다.

해결 방법 :

가능한 해결 방법으로 DataTransfer 개체에 특수 키를 추가하고 테스트했습니다. 예를 들어, 효율성을 높이기 위해 "드래그 오버"가 발생할 때마다 드래그가 시작될 때마다 "드롭 타겟"규칙을 찾아보고 싶었습니다. 이를 위해 각 규칙을 식별하는 키를 dataTransfer 객체에 추가하고 "contains"를 사용하여 테스트했습니다.

ev.originalEvent.dataTransfer.types.includes("allow_drop_in_non_folders")

그리고 그런 것. 분명히 말하면 "포함"은 마법의 총알이 아니며 성능 문제 자체가 될 수 있습니다. 사용법과 시나리오를 잘 이해하십시오.


내 질문에 짧은 대답은 밝혀 : 아니오 WHATWG 규격은 에서 (사양에서 "소스 노드"라고도 함) 드래그 요소의 존재에 대한 참조를 제공하지 않습니다 dragenter, dragover또는 dragleave이벤트를.

왜 안돼? 두 가지 이유 :

첫째, Jeffery가 자신의 의견 에서 지적했듯이 WHATWG 사양은 IE5 +의 드래그 앤 드롭 구현을 기반으로합니다. (이 글을 쓰는 현재 주요 멀티 터치 브라우저는 HTML 드래그 앤 드롭을 구현하지 않습니다.) "싱글 터치"컨텍스트에서 현재 드래그 된 요소에 대한 전역 참조를에 저장하는 것은 쉽습니다 dragstart.

둘째, HTML 끌어서 놓기를 사용하면 여러 문서에서 요소를 끌어다 놓을 수 있습니다. 이 굉장뿐만 아니라 요소의 존재에 대한 참조를 제공하는 모든 끌려 것을 의미한다 dragenter, dragover또는 dragleave이벤트가 이해가되지 것입니다; 다른 문서의 요소를 참조 할 수 없습니다. 드래그가 같은 문서에서 시작 되든 다른 문서에서 시작 되었든 이러한 이벤트가 동일한 방식으로 작동한다는 것은 API의 강점입니다.

그러나 dataTransfer.types(내 작업 솔루션 답변에 설명 된대로) through를 제외한 모든 드래그 이벤트에 직렬화 된 정보를 제공 할 수 없다는 것은 API에서 눈부신 누락입니다. 나는 한 드래그 이벤트의 공공 데이터에 대한 제안서를 제출 WHATWG에, 나는 당신이 당신의 지원을 표현 바랍니다.


(매우 비정상적인) 해결책은 선택기를 객체 의 데이터 유형 으로 저장하는 dataTransfer것입니다. 예 : http://jsfiddle.net/TrevorBurnham/eKHap/

여기에서 활성 라인은

e.dataTransfer.setData('text/html', 'foo');
e.dataTransfer.setData('draggable', '');

그런 다음 dragoverdragenter이벤트 e.dataTransfer.types에는 'draggable'끌고있는 요소를 확인하는 데 필요한 ID 인 문자열이 포함 됩니다. (브라우저 text/html는이 기능이 작동하기 위해 인식 된 MIME 유형에 대해서도 데이터를 설정 해야합니다. Chrome 및 Firefox에서 테스트되었습니다.)

추악하고 추악한 해킹이며 누군가 나에게 더 나은 해결책을 줄 수 있다면 기꺼이 현상금을 줄 것입니다.

업데이트 : 추가 할 가치가있는 한 가지주의 사항은 사양에 모든 데이터 유형이 소문자 ASCII로 변환 될 것이라고 명시되어 있다는 점입니다. 따라서 대문자 또는 유니 코드를 포함하는 선택기가 깨질 것이라는 점에주의하십시오. Jeffery의 솔루션은 이 문제를 회피합니다.


현재 사양을 감안할 때 "해킹"이 아닌 솔루션은 없다고 생각합니다. WHATWG에 청원 하는 것은이 문제를 해결하는 한 가지 방법입니다. :-)

"(매우 비 우아한) 솔루션"확장 ( 데모 ) :

  • 현재 드래그되는 모든 요소의 전역 해시를 만듭니다.

    var dragging = {};
    
  • 에서 dragstart(이미 하나가없는 경우) 핸들러, 요소에 드래그 ID를 할당 글로벌 해시에 요소를 추가 한 후 데이터 유형으로 드래그 ID를 추가합니다 :

    var dragId = this.dragId;
    
    if (!dragId) {
        dragId = this.dragId = (Math.random() + '').replace(/\D/g, '');
    }
    
    dragging[dragId] = this;
    
    e.dataTransfer.setData('text/html', dragId);
    e.dataTransfer.setData('dnd/' + dragId, dragId);
    
  • 에서 dragenter핸들러, 데이터 유형 중 드래그 ID를 찾아 글로벌 해시에서 원래 요소를 검색 :

    var types = e.dataTransfer.types, l = types.length, i = 0, match, el;
    
    for ( ; i < l; i++) {
        match = /^dnd\/(\w+)$/.exec(types[i].toLowerCase());
    
        if (match) {
            el = dragging[match[1]];
    
            // do something with el
        }
    }
    

dragging해시를 자신의 코드에 비공개로 유지하면 타사 코드가 드래그 ID에 액세스 할 수 있어도 원래 요소를 찾을 수 없습니다.

이는 각 요소를 한 번만 드래그 할 수 있다고 가정합니다. 멀티 터치를 사용하면 다른 손가락을 사용하여 동일한 요소를 여러 번 드래그 할 수 있다고 가정합니다.


업데이트 : 동일한 요소에서 여러 드래그를 허용하기 위해 글로벌 해시에 드래그 카운트를 포함 할 수 있습니다. http://jsfiddle.net/jefferyto/eKHap/2/


드래그가 시작될 때 드래그되는 항목을 확인하고 드래그 오버 / 드래 젠터 이벤트가 시작될 때 사용할 변수에 저장할 수 있습니다.

var draggedElement = null;

function drag(event) {
    draggedElement = event.srcElement || event.target;
};

function dragEnter(event) {
    // use the dragged element here...
};

In the drag event, copy event.x and event.y to an object and set it as the value of an expando property on the dragged element.

function drag(e) {
    this.draggingAt = { x: e.x, y: e.y };
}

In the dragenter and dragleave events find the element whose expando property value matches the event.x and event.y of the current event.

function dragEnter(e) {
    var draggedElement = dragging.filter(function(el) {
        return el.draggingAt.x == e.x && el.draggingAt.y == e.y;
    })[0];
}

To reduce the number of elements you need to look at, you can keep track of elements by adding them to an array or assigning a class in the dragstart event, and undoing that in the dragend event.

var dragging = [];
function dragStart(e) {
    e.dataTransfer.setData('text/html', '');
    dragging.push(this);
}
function dragEnd(e) {
    dragging.splice(dragging.indexOf(this), 1);
}

http://jsfiddle.net/gilly3/4bVhL/

Now, in theory this should work. However, I don't know how to enable dragging for a touch device, so I wasn't able to test it. This link is mobile formatted, but touch and slide didn't cause dragging to start on my android. http://fiddle.jshell.net/gilly3/4bVhL/1/show/

Edit: From what I've read, it doesn't look like HTML5 draggable is supported on any touch devices. Are you able to get draggable working on any touch devices? If not, multi-touch wouldn't be an issue and you can resort to just storing the dragged element in a variable.


To check if it is a file use:

e.originalEvent.dataTransfer.items[0].kind

To check the type use:

e.originalEvent.dataTransfer.items[0].type

i.e. I want to allow only one single file jpg, png, gif, bmp

var items = e.originalEvent.dataTransfer.items;
var allowedTypes = ["image/jpg", "image/png", "image/gif", "image/bmp"];
if (items.length > 1 || items["0"].kind != "file" || items["0"].type == "" || allowedTypes.indexOf(items["0"].type) == -1) {
    //Type not allowed
}

Reference: https://developer.mozilla.org/it/docs/Web/API/DataTransferItem


From what I have read on MDN, what you are doing is correct.

MDN lists some recommended drag types, such as text/html, but if none are suitable then just store the id as text using the 'text/html' type, or create your own type, such as 'application/node-id'.


I think you can get it by calling e.relatedTarget See: http://help.dottoro.com/ljogqtqm.php

OK, I tried e.target.previousElementSibling and it works, sorta.... http://jsfiddle.net/Gz8Qw/4/ I think it hangs up because the event is being fired twice. Once for the div and once for the text node (when it fires for text node, it is undefined). Not sure if that will get you where you want to be or not...

참고URL : https://stackoverflow.com/questions/11065803/determine-what-is-being-dragged-from-dragenter-dragover-events

반응형