私のページに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の回答には、ドラッグソースが外部ファイルであるかどうかを確認する関数が含まれています。
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による回答は通常の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でテスト済み。
私は複数のアップロード領域にクラスセレクターを使用しているので、私のソリューションはこのあまり純粋でない形式を取っていました
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);
});
},