브라우저가 끌어서 놓기 파일을로드하지 못하도록 방지


194

내 페이지에 html5 드래그 앤 드롭 업 로더를 추가하고 있습니다.

파일을 업로드 영역에 놓으면 모든 것이 잘 작동합니다.

그러나 실수로 업로드 영역 외부에서 파일을 삭제하면 브라우저가 로컬 파일을 새 페이지 인 것처럼로드합니다.

이 동작을 어떻게 방지 할 수 있습니까?

감사!


2
html5 드래그 앤 드롭 업로드를 처리하기 위해 어떤 코드를 사용하고 있는지 궁금합니다. 감사.
robertwbradford

문제는 e.dataTransfer ()가 누락되었거나 drop / dragenter / etc에서 preventDefault ()가 누락되어 발생합니다. 이벤트. 그러나 코드 샘플 없이는 말할 수 없습니다.
HoldOffHunger

답변:


314

preventDefault()모든 드래그 앤 드롭 이벤트 를 호출하는 이벤트 리스너를 창에 추가 할 수 있습니다 .
예:

window.addEventListener("dragover",function(e){
  e = e || event;
  e.preventDefault();
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
},false);

45
드래그 오버는 내가 놓친 부분입니다.
cgatian

11
브라우저가 삭제 된 파일을로드하지 못하게하려면 처리기 dragoverdrop처리기가 모두 필요하다는 것을 확인 합니다. (Chrome 최신 2015/08/03). 이 솔루션은 최신 FF에서도 작동합니다.
Offirmo

4
이것은 완벽하게 작동하며 resumable.js와 같은 끌어서 놓기 파일 업로드 스크립트의 드롭 이벤트와 같은 드롭 이벤트를 허용하도록 구성된 페이지 요소와 함께 사용할 수 있음을 확인할 수 있습니다. 사용자가 실수로 실제 파일 업로드 드롭 영역 외부에서 업로드하려는 파일을 삭제 한 다음 브라우저 창에서 동일한 파일이 직접 렌더링되는 이유를 궁금해하는 경우 기본 브라우저 동작을 방지하는 것이 유용합니다 ( 파일 또는 동영상 업로드와 같은 호환되는 파일 형식이 삭제되었다고 가정합니다.
bluebinary

15
참고 : 또한 파일을로 드래그 할 수 없습니다 <input type="file" />. e.target파일 입력 여부를 확인 하고 이러한 이벤트를 통과 시켜야합니다 .
Sebastian Nowak

6
뭐 ? 왜 윈도우 드래그로 파일을로드해야합니까? 이것은 말이되지 않습니다 ...
L.Trabacchin

38

많은 문제를 겪은 후 이것이 가장 안정적인 솔루션이라는 것을 알았습니다.

var dropzoneId = "dropzone";

window.addEventListener("dragenter", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
}, false);

window.addEventListener("dragover", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});

window.addEventListener("drop", function(e) {
  if (e.target.id != dropzoneId) {
    e.preventDefault();
    e.dataTransfer.effectAllowed = "none";
    e.dataTransfer.dropEffect = "none";
  }
});
<div id="dropzone">...</div>

창에 조건을 설정 effectAllow하고 dropEffect무조건 설정 하면 속성을 새로 설정했는지 여부에 관계없이 드롭 영역이 더 이상 dnd를 허용하지 않습니다.


e.dataTransfer ()는이 작업을 수행하는 데있어 중요한 부분으로 "허용 된 답변"에서 언급하지 못했습니다.
HoldOffHunger

9

jQuery의 경우 정답은 다음과 같습니다.

$(document).on({
    dragover: function() {
        return false;
    },
    drop: function() {
        return false;
    }
});

다음 return false과 같이 동작합니다 event.preventDefault()event.stopPropagation().


9

일부 요소에서만 끌어서 놓기를 허용하려면 다음과 같이 할 수 있습니다.

window.addEventListener("dragover",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") { // check which element is our target
    e.preventDefault();
  }
},false);
window.addEventListener("drop",function(e){
  e = e || event;
  console.log(e);
  if (e.target.tagName != "INPUT") {  // check which element is our target
    e.preventDefault();
  }  
},false);

나에게 완벽하게 작동하지만 type = file 검사도 추가합니다. 그렇지 않으면 텍스트 입력으로 드래그 할 수 있습니다
Andreas Zwerger

2

이 시도:

document.body.addEventListener('drop', function(e) {
    e.preventDefault();
}, false);

2

기본적으로 모든 끌어서 놓기 작업을 방지하는 것은 원하지 않을 수 있습니다. 적어도 일부 브라우저에서는 드래그 소스가 외부 파일인지 확인할 수 있습니다. 이 StackOverflow answer 에서 드래그 소스가 외부 파일인지 확인하는 기능을 포함 시켰습니다 .

Digital Plane의 답변을 수정하면 다음과 같이 할 수 있습니다.

function isDragSourceExternalFile() {
     // Defined here: 
     // https://stackoverflow.com/a/32044172/395461
}

window.addEventListener("dragover",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);
window.addEventListener("drop",function(e){
    e = e || event;
    var IsFile = isDragSourceExternalFile(e.originalEvent.dataTransfer);
    if (IsFile) e.preventDefault();
},false);

1
요점이 e || event;뭐야? 어디에 event정의되어 있습니까? 신경 쓰지 마. IE의 전역 객체 인 것 같습니다. 이 인용구를 찾았 "In Microsoft Visual Basic Scripting Edition (VBScript), you must access the event object through the window object." 습니다
1.21 기가 와트

2

참고 : OP는 Angular 솔루션을 요청하지 않았지만 여기를 찾아 왔습니다. 따라서 Angular를 사용하는 경우 가능한 해결책으로 찾은 것을 공유하는 것입니다.

내 경험상이 문제는 페이지에 파일 삭제 기능을 추가 할 때 처음 발생합니다. 따라서 내 의견으로는 이것을 추가하는 구성 요소가 드롭 영역 외부로 떨어지는 것을 방지해야 할 책임이 있다고 생각합니다.

내 솔루션에서 드롭 영역은 클래스가있는 입력이지만 모든 선택기가 작동합니다.

import { Component, HostListener } from '@angular/core';
//...

@Component({
  template: `
    <form>
      <!-- ... -->
      <input type="file" class="dropzone" />
    </form>
  `
})
export class MyComponentWithDropTarget {

  //...

  @HostListener('document:dragover', ['$event'])
  @HostListener('drop', ['$event'])
  onDragDropFileVerifyZone(event) {
    if (event.target.matches('input.dropzone')) {
      // In drop zone. I don't want listeners later in event-chain to meddle in here
      event.stopPropagation();
    } else {
      // Outside of drop zone! Prevent default action, and do not show copy/move icon
      event.preventDefault();
      event.dataTransfer.effectAllowed = 'none';
      event.dataTransfer.dropEffect = 'none';
    }
  }
}

리스너는 컴포넌트가 작성 / 파기 될 때 자동으로 추가 / 제거되며 동일한 페이지에서 동일한 전략을 사용하는 다른 컴포넌트는 stopPropagation ()으로 인해 서로 간섭하지 않습니다.


이것은 매력처럼 작동합니다! 브라우저는 심지어 금지 아이콘을 추가하여 마우스 커서를 변경합니다!
pti_jul

1

몇 가지 다른 답변에 요약 된 "대상 확인"방법을 기반으로보다 일반적인 / 기능적 방법은 다음과 같습니다.

function preventDefaultExcept(predicates) {
  return function (e) {
    var passEvery = predicates.every(function (predicate) { return predicate(e); })
    if (!passEvery) {
      e.preventDefault();
    }
  };
}

다음과 같이 호출됩니다.

function isDropzone(e) { return e.target.id === 'dropzone'; }
function isntParagraph(e) { return e.target.tagName !== 'p'; }

window.addEventListener(
  'dragover',
  preventDefaultExcept([isDropzone, isntParagraph])
);
window.addEventListener(
  'drop',
  preventDefaultExcept([isDropzone])
);

또한 여기에 ES6을 추가 할 수 있습니다 function preventDefaultExcept(...predicates){}. 그리고 다음과 같이 사용하십시오preventDefaultExcept(isDropzone, isntParagraph)
hlfrmn

0

페이지의 너비와 높이를 채우는 HTML object( embed)이 있습니다. @ digital-plane의 대답은 일반 웹 페이지에서는 작동하지만 사용자가 포함 된 개체 위에 놓이면 작동하지 않습니다. 그래서 다른 해결책이 필요했습니다.

이벤트 캡처 단계 를 사용하도록 전환 하면 내장 객체가 이벤트를 수신하기 전에 이벤트를 가져올 수 있습니다 ( true이벤트 리스너 호출 종료시 값에 주목 ).

// document.body or window
document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop", function(e){
  e = e || event;
  e.preventDefault();
  console.log("drop true");
}, true);

@ digital-plane의 답변에 따라 다음 코드를 사용하면 페이지가 드래그 대상이되어 객체 임베드가 이벤트를 캡처하지 못하게하고 이미지를로드합니다.

document.body.addEventListener("dragover", function(e){
  e = e || event;
  e.preventDefault();
  console.log("over true");
}, true);

document.body.addEventListener("drop",function(e){
  e = e || event;
  e.preventDefault();
  console.log("Drop true");

  // begin loading image data to pass to our embed
  var droppedFiles = e.dataTransfer.files;
  var fileReaders = {};
  var files = {};
  var reader;

  for (var i = 0; i < droppedFiles.length; i++) {
    files[i] = droppedFiles[i]; // bc file is ref is overwritten
    console.log("File: " + files[i].name + " " + files[i].size);
    reader = new FileReader();
    reader.file = files[i]; // bc loadend event has no file ref

    reader.addEventListener("loadend", function (ev, loadedFile) {
      var fileObject = {};
      var currentReader = ev.target;

      loadedFile = currentReader.file;
      console.log("File loaded:" + loadedFile.name);
      fileObject.dataURI = currentReader.result;
      fileObject.name = loadedFile.name;
      fileObject.type = loadedFile.type;
      // call function on embed and pass file object
    });

    reader.readAsDataURL(files[i]);
  }

}, true);

Mac의 Firefox에서 테스트되었습니다.


0

여러 업로드 영역에 클래스 선택기를 사용하므로 솔루션이 덜 순수한 형태를 취했습니다.

jQuery에 의존하는 Axel Amthor의 답변을 기반으로 ($에 해당)

_stopBrowserFromOpeningDragAndDropPDFFiles = function () {

        _preventDND = function(e) {
            if (!$(e.target).is($(_uploadBoxSelector))) {
                e.preventDefault();
                e.dataTransfer.effectAllowed = 'none';
                e.dataTransfer.dropEffect = 'none';
            }
        };

        window.addEventListener('dragenter', function (e) {
            _preventDND(e);
        }, false);

        window.addEventListener('dragover', function (e) {
            _preventDND(e);
        });

        window.addEventListener('drop', function (e) {
            _preventDND(e);
        });
    },
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.