내 페이지에 html5 드래그 앤 드롭 업 로더를 추가하고 있습니다.
파일을 업로드 영역에 놓으면 모든 것이 잘 작동합니다.
그러나 실수로 업로드 영역 외부에서 파일을 삭제하면 브라우저가 로컬 파일을 새 페이지 인 것처럼로드합니다.
이 동작을 어떻게 방지 할 수 있습니까?
감사!
내 페이지에 html5 드래그 앤 드롭 업 로더를 추가하고 있습니다.
파일을 업로드 영역에 놓으면 모든 것이 잘 작동합니다.
그러나 실수로 업로드 영역 외부에서 파일을 삭제하면 브라우저가 로컬 파일을 새 페이지 인 것처럼로드합니다.
이 동작을 어떻게 방지 할 수 있습니까?
감사!
답변:
preventDefault()
모든 드래그 앤 드롭 이벤트 를 호출하는 이벤트 리스너를 창에 추가 할 수 있습니다 .
예:
window.addEventListener("dragover",function(e){
e = e || event;
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
},false);
dragover
와 drop
처리기가 모두 필요하다는 것을 확인 합니다. (Chrome 최신 2015/08/03). 이 솔루션은 최신 FF에서도 작동합니다.
<input type="file" />
. e.target
파일 입력 여부를 확인 하고 이러한 이벤트를 통과 시켜야합니다 .
많은 문제를 겪은 후 이것이 가장 안정적인 솔루션이라는 것을 알았습니다.
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를 허용하지 않습니다.
일부 요소에서만 끌어서 놓기를 허용하려면 다음과 같이 할 수 있습니다.
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);
기본적으로 모든 끌어서 놓기 작업을 방지하는 것은 원하지 않을 수 있습니다. 적어도 일부 브라우저에서는 드래그 소스가 외부 파일인지 확인할 수 있습니다. 이 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);
e || event;
뭐야? 어디에 event
정의되어 있습니까? 신경 쓰지 마. IE의 전역 객체 인 것 같습니다. 이 인용구를 찾았 "In Microsoft Visual Basic Scripting Edition (VBScript), you must access the event object through the window object."
습니다
참고 : 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 ()으로 인해 서로 간섭하지 않습니다.
몇 가지 다른 답변에 요약 된 "대상 확인"방법을 기반으로보다 일반적인 / 기능적 방법은 다음과 같습니다.
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])
);
function preventDefaultExcept(...predicates){}
. 그리고 다음과 같이 사용하십시오preventDefaultExcept(isDropzone, isntParagraph)
페이지의 너비와 높이를 채우는 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에서 테스트되었습니다.
여러 업로드 영역에 클래스 선택기를 사용하므로 솔루션이 덜 순수한 형태를 취했습니다.
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);
});
},