JavaScripでondrop
とondragover
を使用した時にちょっとハマったので、今回はこの2つのイベントについてまとめてみました。
最初にJavaScriptのondrop
とondragover
のイベントの説明を簡単にします。
画像をドロップして、画面に表示する簡単なサンプルコードを作成したので、それを元にコードの解説しています。
ondrop, ondragoverイベントとは?
ondrop
イベントは要素に指定すると、その要素に対してファイルなどをドロップしたときに発生するイベントです。
ondragover
イベントは指定した要素の上に、ファイルなどをドラッグした時に発生するイベントです。
ドラッグ中は数百ミリ秒間隔で、ずっと発生します。
それぞれのイベントについては、MDNのこちらに詳しく書いてあります。
HTML ドラッグ&ドロップ API
`ondrop`だけで動くかと思っていましたが、使ってみると要素に対して、`ondragover`も設定していないとイベントがおきませんでした。
画像をドロップして表示するサンプルコード
画像ファイルを画面の特定の位置にドロップして、そのまま画面の下部に表示するようなものを作成してみました。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>drag on drop</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script>
function fileDragOver(e) {
e.preventDefault()
}
function fileDrop(e) {
e.preventDefault()
const files = e.dataTransfer.files
for (var i = 0; i < files.length; i++) {
const file = files[i]
const reader = new FileReader()
reader.onload = (event) => {
const base64Text = event.currentTarget.result
document.querySelector('#uploadImageArea').innerHTML += `<img src="${base64Text}" width="20%" />`
}
reader.readAsDataURL(file)
}
}
</script>
</head>
<body>
<nav class="navbar navbar-dark bg-dark mb-3">
<a class="navbar-brand ms-3" href="#">Drag On Drop</a>
</nav>
<div class="container">
<form>
<div ondrop="fileDrop(event)" ondragover="fileDragOver(event)" class="mb-3 d-flex justify-content-center border rounded">
<div class="p-5">
ここにドラッグ&ドロップ
</div>
</div>
<div id="uploadImageArea" class="d-flex flex-wrap"></div>
</form>
</div>
</body>
</html>
解説
HTMLタグから見ていきます。
div
タグに対して、ondrop
・ondragover
を設定して、ドラッグ&ドロップするエリアを下記のように作成しています。
<div ondrop="fileDrop(event)" ondragover="fileDragOver(event)" class="mb-3 d-flex justify-content-center border rounded">
<div class="p-5">
ここにドラッグ&ドロップ
</div>
</div>
このエリアにファイルをドロップすると、ondrop
・ondragover
のイベントが発生します。
ファイルをエリアに持っていった時に、マウスポインタがエリアにある間はondragover
がずっと発生して、ファイルを落とした時にondrop
が発生します。
ondrop
イベントの時にはfileDrop
関数を呼び、ondragover
の時にはfileDragOver
関数を呼んでいます。
それぞれの関数が呼ばれた時には、引数としてDragEvent
オブジェクトが渡されます。
次にスクリプトを見ていきます。
まず最初に、それぞれの関数でpreventDefault
メソッドを呼ぶようにしています。
e.preventDefault()
これを行うことで、画像ファイルをドラッグ&ドロップした場合に、ブラウザ標準の画像をそのまま開くという挙動を抑えています。
fileDrop
関数はファイルをドロップした時に動きます。
preventDefault
を呼んだ後は、ファイルを取得して、画面に表示するということを行っています。
DragEvent
オブジェクトのdataTransfer.files
で、ドロップされたファイルがFileList
オブジェクト形式で取得できます。
内容をfiles
変数に入れています。
const files = e.dataTransfer.files
ドロップされたファイルの数はlength
を調べるとわかります。
for文を使用して、下記のようにすることで、全てのファイルを取得することが可能です。
1個だけしか処理しない場合は、e.dataTransfer.files[0]
として、取得しても良いかもしれません。
for (var i = 0; i < files.length; i++) {
const file = files[i]
const reader = new FileReader()
reader.onload = (event) => {
const base64Text = event.currentTarget.result
document.querySelector('#uploadImageArea').innerHTML += `<img src="${base64Text}" width="20%" />`
}
reader.readAsDataURL(file)
}
for文の中では、最初にfiles
の要素番号を指定して、ファイルを取得しています。
その後に、FileReader
を使用して、ファイルの内容を読み込んでいます。
reader.readAsDataURL
は非同期でファイルの内容を読みます。
読み終わると、reader.onload
に設定した関数が動きます。
#uploadImageArea
がついているdiv
タグ内に展開しています。base64で画像を取得するところについては、下記に詳しく書いたので確認してみてください。
動作確認をする
実際に作ったものを動かすと、下記のようになります。
画像を選択して、ドロップすると画面に表示されることが確認できました。
ドロップした後にアップロードしたい
ドロップした後にファイルをアップロードしたい場合は、今回取得したFileList
オブジェクトを下記のようなinput
タグに設定して、送信するといいです。
<input type="file" name="file[]" multiple />
jQueryを使っていますが、アップロードまで検証した記事が下記になります。
ドラッグ&ドロップでマルチファイルアップロードのサンプルと懸念事項
ajaxを使用して、アップロードしたい場合には、今回取得したbase64文字列の画像をjsonに載せて送信すると良いです。
コメント