브라우저가 끌어서 놓기 파일을로드하지 못하도록 방지
내 페이지에 html5 드래그 앤 드롭 업 로더를 추가하고 있습니다.
파일을 업로드 영역에 놓으면 모든 것이 잘 작동합니다.
그러나 실수로 업로드 영역 외부에서 파일을 삭제하면 브라우저가 로컬 파일을 새 페이지 인 것처럼로드합니다.
이 동작을 어떻게 방지 할 수 있습니까?
감사!
preventDefault()모든 드래그 앤 드롭 이벤트 를 호출하는 이벤트 리스너를 창에 추가 할 수 있습니다 .
예:
window.addEventListener("dragover",function(e){
e = e || event;
e.preventDefault();
},false);
window.addEventListener("drop",function(e){
e = e || event;
e.preventDefault();
},false);
많은 문제를 겪은 후 이것이 가장 안정적인 솔루션이라는 것을 알았습니다.
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를 허용하지 않습니다.
jQuery의 경우 정답은 다음과 같습니다.
$(document).on({
dragover: function() {
return false;
},
drop: function() {
return false;
}
});
다음 return false과 같이 동작합니다 event.preventDefault()및 event.stopPropagation().
일부 요소에서만 끌어서 놓기를 허용하려면 다음과 같이 할 수 있습니다.
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);
이 시도:
document.body.addEventListener('drop', function(e) {
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);
몇 가지 다른 답변에 요약 된 "대상 확인"방법을 기반으로보다 일반적인 / 기능적 방법은 다음과 같습니다.
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])
);
페이지의 너비와 높이를 채우는 HTML object( embed)이 있습니다. @ digital-plane의 대답은 일반 웹 페이지에서는 작동하지만 사용자가 포함 된 개체 위에 놓인 경우에는 작동하지 않습니다. 그래서 다른 해결책이 필요했습니다.
If we switch to using the event capture phase we can get the events before the embedded object receives them (notice the true value at the end of the event listener call):
// 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);
Using the following code (based on @digital-plane's answer) the page becomes a drag target, it prevents object embeds from capturing the events and then loads our images:
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);
Tested on Firefox on Mac.
I am using a class selector for multiple upload areas so my solution took this less pure form
Based on Axel Amthor's answer, with dependency on jQuery (aliased to $)
_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);
});
},
Note: Although the OP did not ask for an Angular solution, I came here looking for that. So this is to share what I found to be a viable solution, if you use Angular.
In my experience this problem first arises when you add file drop functionality to a page. Therefore my opinion is that the component that adds this, should also be responsible for preventing drop outside of the drop zone.
In my solution the drop zone is an input with a class, but any unambiguous selector works.
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';
}
}
}
The listeners are added/removed automatically when component is created/destroyed, and other components using the same strategy on the same page do not interfere with each other due to the stopPropagation().
참고URL : https://stackoverflow.com/questions/6756583/prevent-browser-from-loading-a-drag-and-dropped-file
'Programming' 카테고리의 다른 글
| HTML5 캔버스에서 단일 픽셀을 설정하는 가장 좋은 방법은 무엇입니까? (0) | 2020.05.24 |
|---|---|
| Rust에서 사용하지 않는 코드 경고를 비활성화하는 방법은 무엇입니까? (0) | 2020.05.24 |
| Vim 또는 Linux에서 공백을 탭으로 변환하는 방법은 무엇입니까? (0) | 2020.05.24 |
| 이벤트 핸들러가 이미 추가 되었습니까? (0) | 2020.05.24 |
| 리플렉션을 통해 Java 클래스가 추상적인지 여부를 어떻게 확인할 수 있습니까? (0) | 2020.05.24 |