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
の両方を無条件に設定すると、プロパティが新規に設定されているかどうかにかかわらず、ドロップゾーンはd-n-dを受け入れなくなります。
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])
);
複数のアップロード領域にクラスセレクターを使用しているため、ソリューションはこのあまり純粋でない形式を取りました。
Axel Amthorの回答に基づき、jQueryに依存($にエイリアス)
_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);
});
},
ページの幅と高さを埋めるHTML object
(embed
)があります。 @ digital-planeによる回答は、通常のWebページで機能しますが、ユーザーが埋め込みオブジェクトにドロップした場合は機能しません。そのため、別のソリューションが必要でした。
イベントキャプチャフェーズ を使用するように切り替えると、埋め込みオブジェクトがイベントを受け取る前にイベントを取得できます(イベントリスナー呼び出しの最後に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でテスト済み。