はじめに
ファイルアップロードのUIを自前で実装しようとすると、想像以上に手間がかかります。dragenter・dragover・dropのイベントを個別にハンドリングし、FileReaderで画像プレビューを作り、XMLHttpRequestで進捗を拾い、複数ファイルやバリデーションにも対応して……と積み上げていくと、あっという間にコード量が膨らんでしまいます。
Dropzoneは、こうしたドラッグ&ドロップアップロードの実装を、ほとんど設定だけで済ませてくれるJavaScriptライブラリです。極端な話、HTML要素にclass="dropzone"を付けるだけでも動き出します。今回はDropzoneの特徴から、ブラウザ上で実際に触れるサンプルを交えた実践的な使い方までを紹介します。
とはいえ、説明より先に触ってみたほうが早いと思います。下のサンプル節では、画像をドラッグ&ドロップするとその場でサムネイルが表示されるデモを動かせます。先に挙動を見たい方はこちらからどうぞ。
Dropzoneとは
Dropzoneは「an easy to use drag'n'drop library」を謳うJavaScriptライブラリで、GitHub上で18,000以上のスターを集めている定番のファイルアップロードUIライブラリです。jQueryなどの外部フレームワークに依存しないvanilla JSで書かれており、npm・CDNのどちらからでも導入できます。
現在は次期メジャーバージョンとなる6.0.0系がベータ公開されており、IEサポートを廃止してよりモダンなブラウザ向けに軽量化が進められています。
主な特徴
- Auto Discover - HTML要素に
class="dropzone"を付けるだけで、JavaScriptを1行も書かずに自動初期化されます - 画像プレビューが標準搭載 - 選択・ドロップした画像は、追加のライブラリなしでサムネイルとして自動表示されます
- 進捗バー・イベントが充実 - アップロードの進捗やエラーをプログレスバーで表示しつつ、
addedfile・success・errorなど豊富なイベントで細かく制御できます - 柔軟なバリデーション -
acceptedFiles・maxFilesize・maxFilesといったオプションだけで、ファイル形式・サイズ・枚数の制限を実装できます - テンプレートのカスタマイズ -
previewTemplateオプションでプレビューのHTML自体を差し替えられ、デザインを自由に調整できます
インストール
npm・yarnからインストールできます。
npm install dropzone
# または
yarn add dropzone
バンドラーを使わない場合は、CDN経由でJSとCSSを直接読み込むこともできます。
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/dropzone/dist/dropzone.css" />
<script type="module">
import { Dropzone } from 'https://cdn.jsdelivr.net/npm/dropzone/+esm'
</script>
Dropzoneのサンプルを動かす
Dropzoneは対象の要素をnew Dropzone()に渡すだけで、ドラッグ&ドロップ対応のアップロードエリアに変換してくれます。画像を追加すると、Dropzoneが自動でサムネイルを生成してプレビュー表示してくれるのがポイントです。要点は次のとおりです。
import { Dropzone } from 'dropzone'
// 自動初期化(Auto Discover)を無効にしてから手動で初期化する
Dropzone.autoDiscover = false
const dropzone = new Dropzone('#drop-area', {
url: '/upload',
acceptedFiles: 'image/*',
addRemoveLinks: true,
})
dropzone.on('addedfile', (file) => {
console.log(`追加されました: ${file.name}`)
})
実際に動かせるのが下のサンプルです。手元の画像ファイルをドラッグ&ドロップ、またはクリックして選択してみてください。このデモではアップロード先のサーバーを用意していないためautoProcessQueue: falseを指定し、実際の送信は行わずプレビューの生成だけを確認できるようにしています。
画像をドロップすると、DropzoneがFileReaderを使って自動的にサムネイルを生成し、ファイル名とともに一覧表示してくれるのが分かります。addRemoveLinks: trueによって表示される削除リンクを押すと、removedfileイベントが発火してプレビューから取り除かれます。acceptedFilesの値を'.pdf,.zip'のように変えると、画像以外のファイルを受け付ける設定に切り替えられます。
基本的な使い方
DropzoneはHTML側にclass="dropzone"を付けるだけでも動作します。この場合、JavaScriptを書かなくても自動的にDropzoneインスタンスが生成される「Auto Discover」という仕組みが働きます。
<form action="/upload" class="dropzone" id="my-dropzone"></form>
細かく設定を制御したい場合は、Dropzone.autoDiscover = falseで自動初期化を止めたうえで、new Dropzone()を自分で呼び出します。
import { Dropzone } from 'dropzone'
import 'dropzone/dist/dropzone.css'
Dropzone.autoDiscover = false
const dropzone = new Dropzone('#my-dropzone', {
url: '/upload',
paramName: 'file',
maxFilesize: 5, // MB単位
acceptedFiles: 'image/*',
})
dropzone.on('success', (file, response) => {
console.log('アップロード成功:', response)
})
dropzone.on('error', (file, errorMessage) => {
console.error('アップロード失敗:', errorMessage)
})
urlにはアップロード先のエンドポイントを指定し、success・errorイベントでサーバーからのレスポンスに応じた後処理を書くのが基本の流れです。
実践的なユースケース
ファイルの種類とサイズを制限する
アップロードを受け付けるファイルには、多くの場合「画像だけ」「◯MB以内」「◯枚まで」といった制限が必要になります。DropzoneはacceptedFiles・maxFilesize・maxFilesというオプションを設定するだけで、これらのバリデーションをすべて任せられます。範囲外のファイルはerrorイベントで、枚数超過はmaxfilesexceededイベントで検知できます。
const dropzone = new Dropzone('#drop-area', {
url: '/upload',
acceptedFiles: 'image/*',
maxFilesize: 2, // MB
maxFiles: 3,
})
dropzone.on('error', (file, message) => {
console.log(`エラー: ${file.name} - ${message}`)
})
dropzone.on('maxfilesexceeded', (file) => {
dropzone.removeFile(file) // 上限を超えた分は取り除く
})
実際に動かせるのが下のサンプルです。画像以外のファイルや2MBを超えるファイルをドロップするとエラーメッセージが表示され、4枚目以降を追加すると自動的に除外されます。
maxFilesizeの値を0.1のように小さくすると、ほとんどのファイルがエラーになる様子を確認できます。acceptedFilesを'image/png'のようにMIMEタイプを1つに絞ると、PNG以外はすべて拒否されるようになります。
手動でアップロードキューを制御する
フォームの他の入力項目がすべて埋まってから一括送信したい、といった場面では、ファイルを選んだ瞬間に自動アップロードされては困ります。autoProcessQueue: falseを指定すると、ファイルは追加されるだけでキューに留まり、任意のタイミングでprocessQueue()を呼び出すまでアップロードが始まりません。
const dropzone = new Dropzone('#drop-area', {
url: '/upload',
autoProcessQueue: false,
})
document.getElementById('upload-btn').addEventListener('click', () => {
dropzone.processQueue() // ここで初めてアップロードが始まる
})
下のサンプルはアップロード先のサーバーを持たないため、実際の通信の代わりにdropzone.emit()でprocessing・uploadprogress・successイベントを擬似的に発火させ、進捗バーの動きを再現しています。「アップロード開始」ボタンを押すと、キューにあるファイルの進捗が順番に進んでいきます。
ファイルを追加してから「アップロード開始」を押すと、プレビューに進捗バーが現れて100%まで進み、完了するとチェックマーク付きの成功表示に切り替わります。実際のプロジェクトでは、このprocessQueue()が本物のXMLHttpRequestを発火させ、uploadprogress・success・errorが実際の通信結果に応じて呼ばれる形になります。
プレビューの見た目をカスタムテンプレートで変える
デフォルトのプレビューデザインをそのまま使わず、自分のサイトのデザインに合わせたい場合は、previewTemplateオプションにHTML文字列を渡すことで見た目を丸ごと差し替えられます。data-dz-name・data-dz-size・data-dz-thumbnail・data-dz-removeといった属性が、Dropzoneが値を自動で書き込むためのフックになります。
const dropzone = new Dropzone('#drop-area', {
url: '/upload',
previewTemplate: `
<div class="dz-preview">
<img data-dz-thumbnail />
<div data-dz-name></div>
<div data-dz-size></div>
<button data-dz-remove>削除</button>
</div>
`,
})
実際にカスタムテンプレートでプレビューが表示される様子を確認できるサンプルが以下です。
見た目がデフォルトの縦積みカードから、サムネイル・ファイル名・削除ボタンが横並びになったシンプルなリスト表示に変わったのが分かります。テンプレート内のCSSやレイアウトを書き換えるだけで、標準のプレビューUIに縛られずに自由なデザインを組み込めます。
まとめ
Dropzoneを使うと、ドラッグ&ドロップ対応・画像プレビュー・進捗表示・バリデーションといったファイルアップロードUIに必要な要素を、最小限の設定だけで実装できます。class="dropzone"を付けるだけの手軽さから、previewTemplateによるデザインの作り込みまで対応幅が広いので、プロトタイプから本番プロジェクトまで幅広く使えるライブラリです。
まずは今回のサンプルを手元で編集しながら、自分のプロジェクトに合わせたオプションを探してみてください。