2021-11-01/2023-05-23

Dropzone.jsでファイルアップロードのUXを高める

Dropzone.jsでファイルアップロードのUXを高める

フォームでファイルを取り扱うときによく使うのは「<input type=”file” …」という形ですよね。

ただ、これ使うとローカルのファイルパスが取得できても、ファイルのプレビューなど表示することができません。

それにいちいちボタンクリックして、ファイルあるところまで移動してというのも面倒です。

そこで便利なのが、「Dropzone.js」というjavascriptのライブラリです。

ドラッグ&ドロップでファイルを選択可能で、クリックでも選択可能な上、選択後にアップロードさせることも可能な優れものです。

オープンソースで「MIT LICENSE」なのでお手軽に導入できます。

実際に使ってみた感じは以下です。

※現在はアップロード先がないので、アップロード後の挙動がエラーになってしまっています。

今回はこのDropbox.jsの使い方について説明していきます。

ドキュメントはありますが、実際に使用するとなるとコードを読まないといけないぐらい薄い感じの説明です。

なので、実際に導入できるぐらいのレベルぐらい説明出来たらと思います。

バックエンドはPHPでさらっとしか説明しないので、利用環境に併せて調整してください。

Dropzone.jsの導入

導入は簡単です。

npmの場合

[root@localhost] #npm install --save dropzone

HTML読み込み

<script src="https://unpkg.com/dropzone@5/dist/min/dropzone.min.js"></script>
<link rel="stylesheet" href="https://unpkg.com/dropzone@5/dist/min/dropzone.min.css" type="text/css" />

npmの場合はimportで読み込んで使用できます。

デフォルトが「ECMAScript」になっています。「CommonJS」も利用できます。詳しくはこちら

以下説明は「HTML読み込み」を前提としています。

基本形

基本形はとても簡単で「form」タグのみでOKです。

<form action="/file-upload" class="dropzone" id="my-awesome-dropzone"></form>
<script>Dropzone.discover();</script><!-- ver 6以上 -->

クラス名の「dropzone」を自動で探し出して自動で冒頭のようなドラッグ&ドロップゾーンが作成されます。

デフォルトの挙動ではファイルをドロップすると「form」タグに設定してある「action」にPOSTで送信されます。

デフォルトだどドラッグ&ドロップゾーンが英語なので、少しだけ手を加えましょう。

<form action="/file-upload" class="dropzone" id="my-awesome-dropzone">
<div class="dz-default dz-message">
<button class="dz-button" type="button">ファイルをドラッグ&ドロップしてしてください。<br>またはここをクリック(タップ)して画像選択してください。</button>
</div>
</form>

「dz-message」クラスを元にデフォルトのテキストを挿入するか判定しています。

なので、あらかじめ「dz-message」を付与したブロックを作成しておけば、作成したものが優先されます。オプションで設定することも可能です。(後述)

上の例はデフォルトの挿入形をもとにメッセージのみ変更しています。

ファイルのアップロードのみを目的としてDropzoneを導入する場合はこれでも良さそうです。

ただし実際にはもう少し変更したいなどあると思いますので、オプションについても触れていきます。

オプション等

すべてのオプションは紹介しません。それならドキュメント見た方がさすがに良いと思います。

利用頻度が高そうなところを紹介していきます。

url

(デフォルト) null

これはアップロード先の設定になります。

先ほどのシンプルな例のようにformそのものに「dropzone」クラスを設定する場合は必要ありません。formにactionを設定しますからね。

後述のように「div」に「dropzone」を付与したい場合などには必須になります。

timeout

(デフォルト) null

アップロードに制限時間を設けたい場合に使用可能です。

単位はms。

parallelUploads

(デフォルト) 2

平行してアップロードするファイルの数です。

あまり大きな数を設定するとサーバー側の負担になる可能性があります。

uploadMultiple

(デフォルト) false

1つのリスクエストで複数のファイルを送付するかどうかです。

maxFilesize

(デフォルト) 256

ファイルの最大サイズを設定できます。

設定した値に「1024 × 1024」されます。(MB)

createImageThumbnails

(デフォルト) true

サムネイルを作成するかどうかを選択できます。

offにする場合は「false」を設定。

thumbnailWidth

(デフォルト) 120

サムネイルの幅設定ができます。

nullを設定すると画像比の応じて適当な値が設定されます。

thumbnailHeight

(デフォルト) 120

サムネイルの高さを設定することができます。

横幅同様にnullを設定すると画像比に応じて設定されます。

幅、高さともにnullの場合はリサイズがされないので注意しましょう。

thumbnailMethod

(デフォルト) crop

サムネイルの作成方法を選択できます。

デフォルトは「crop」で上で指定した高さ、幅で切り取られます。

「contain」を設定すると比率を維持したまま作成がされます。

maxFiles

(デフォルト) null

処理可能なファイルの数を設定できます。

すべての処理段階における処理可能な数です。

1を設定すると、他のファイルをアップロード待ちのキューに追加することもできなくなります。

headers

(デフォルト) null

送信時のheaderを設定できます。

認証など設けるときに活用しましょう。

acceptedFiles

(デフォルト) null

ファイルタイプを制限できます。

「,」区切りで文字列と指定可能です。

例)「.jpeg,.jpg,.png」

autoProcessQueue

(デフォルト) true

自動でファイルのアップロードが開始されます。

falseを設定するとキューが自動的に処理されることはなくなります。

falseにした場合は自身で「processQueue()」で処理をさせる記述が必要になります。

autoQueue

(デフォルト) true

選択されたファイルが自動的にキューに追加されます。

falseでキューに追加しないことも可能です。

falseにした場合は自身で「enqueueFile(file)」でキューに追加させる必要があります。

addRemoveLinks

(デフォルト) false

ドロップゾーン内のファイルプレビューを削除することができます。

アップロード中のファイルもキャンセルされます。

previewsContainer

(デフォルト) null

ファイルを選択した後のサムネイル表示部分のカスタマイズができます。

後述で詳しく説明します。

disablePreviews

(デフォルト) false

プレビューエリアを非表示にすることが可能です。

オプション等(対日本人)

デフォルトではあらゆるメッセージが英語です。

オプションの設定やイベント次第でメッセージ事態ほとんど表示させないことも可能ですが、多くの場合は必要になると思います。

dictDefaultMessage

(デフォルト) Drop files here to upload

ドロップゾーンに表示されるメッセージです。

序盤の例をもとにすると「ファイルをドラッグ&ドロップしてしてください。<br>またはここをクリック(タップ)して画像選択してください。」を代入すればOKです。

dictFileTooBig

(デフォルト) File is too big ({{filesize}}MiB). Max filesize: {{maxFilesize}}MiB.

ファイルサイズが設定値より大きい( maxFilesize )場合にエラーメッセージとして表示されます。

dictInvalidFileType

(デフォルト) You can’t upload files of this type.

サポートしていない( acceptedFiles )場合にエラーメッセージとして表示されます。

dictMaxFilesExceeded

(デフォルト) You can not upload any more files.

最大実行ファイル数( maxFiles )に達した場合に表示されます。

オプションの設定方法

序盤の基本的な例だとどうやってオプションを設定すれば良いのか不明ですよね。

そこでどのようにオプションを設定するのか説明します。

  • 自動でドロップゾーンが展開されるのをoff
  • インスタンスを作成
  • 作成の際にオプションを設定

の順で行います。

自動でドロップゾーンが展開されるのをoff ( < ver 6 )

基本的な例をもとに一文追加します。

<form action="/file-upload" class="dropzone" id="my-awesome-dropzone">
<div class="dz-default dz-message">
<button class="dz-button" type="button">ファイルをドラッグ&ドロップしてしてください。<br>またはここをクリック(タップ)して画像選択してください。</button>
</div>
</form>
<!-- ↓これ -->
<script>Dropzone.autoDiscover = false;</script>

「Dropzone.autoDiscover = false」を記述することで自動でドロップゾーンが作成されるのを停止できます。

jsファイルに含める場合はDropzoneのjsファイルが読み込まれた後に記述するようにしてください。

この一文のみインラインという形でも良いと思います。

インスタンスを作成

文字通りインスタンスの生成を行います。

対象となるセレクタを設定してください。

const dropzone = new Dropzone( '#my-awesome-dropzone' );

作成の際にオプションを設定

先ほどのインスタンス作成時の第二引数でオプションを設定できます。

「オプション等」の項目を指定することで変更できます。

const dropzone = new Dropzone( '#my-awesome-dropzone', {
maxFilesize: 3,
addRemoveLinks: true
} );

上の例では最大サイズの指定と、プレビューの削除リンクを指定しています。

イベントの設定

続いてイベントの設定です。

「キューに追加されたとき」「アップロードした時」「完了したとき」などの設定です。

デフォルトのイベントはそのままに追加で処理する方法を見ていきます。

使い所の多いののみ紹介していきます。すべて知りたい場合は「option.js」の中をみてください。

// 設定方法
dropzone.on( 'addedfile', file => {
console.log( file );
} );

addedfile

引数 file

ファイルをキューに追加した時に呼び出されます。

デフォルトだとキューへの追加は自動なので、ファイルが選択されるとすぐにコールされます。

removedfile

引数 file

ドロップゾーンからファイルが取り除かれた際にコールされます。

error

引数 file, message

エラーが起きた際に呼び出されます。

messageにはエラーメッセージが入っています。

success

引数 file

アップロードが終了かつ成功した時に呼び出されます。

バックエンド側で何か返却し、フロント側で処理をする際に便利です。fileのxhr内responseで受け取れます。

complete

引数 file

成功でも失敗でも対象ファイルの処理が終了したら呼び出されます。

処理開始になにか仕込んだ場合は、ここで終了処理させると良いです。

メソッド

メソッドは基本的に使用しなくても良いです。

オプションで自動処理を止めた場合やイベントを設定する場合に使用する場合があります。

使用しそうなメソッドのみピックアップしています。

processQueue()

現在キューにあるファイルのアップロードが開始されます。

オプション「autoProcessQueue」でfalseにした場合に使用します。

enqueueFile()

引数 file

引数のファイルをキューに追加します。

オプション「autoQueue」でfalseにした場合に使用します。

disable()

ドロップゾーンを使用不可にします。

アップロード中のファイルもキャンセルされます。

enable()

disable状態を解除し、ドロップゾーンを正常に利用できるようになります。

displayExistingFile()

引数 mockfile, image_url, callback, crossorigin, resizeThumbnail

プレビューエリアにファイルを表示します。

初期表示時にファイルを表示したい場合などに利用できます。

後述で使用しています。

getQueuedFiles()

キューに追加されているファイルを取得できます。

すべてのファイルを取得する場合は「dropzone.files」で取得可能。

getUploadingFiles()

アップロード中のファイルを取得できます。

実用例

続いて実用例について紹介していきます。

こういうパターンありそうかなというのを取り上げています。

form以外の要素に使用したい

div要素の「dropzone」クラスに対してインスタンスを生成しています。

フォームではないのでオプションで「url」が必須な点に注意してください。

また、デフォルトのメッセージを変更しています。

複数のドロップゾーンを使用したい

アップロード先を分けたい場合に便利かと思います。

「dropzone」クラスのdivをすべて取得し、それぞれに設定してある「data-upload」をupload先に指定しています。

デフォルトテンプレートの変更をしたい

「previewTemplate」で表示したいテンプレートを選択しています。

今回はチェックマーク、エラーマークを任意のものに変えたテンプレートを設定しました。

デフォルトのテンプレート大幅に変更しすぎるとうまく動作しなくなる可能性もあるので、クラス名などそのままにところどころ変更していくのが良いです。

完全にオリジナルにする場合は、デフォルトのメソッドをオーバーライドして書き換える必要性が出てきます。

削除ボタンを表示したい

上のドロップゾーンはオプションを利用したものです。

下のドロップゾーンはテンプレートに「data-dz-remove」を設定したものを設置したものです。

上のドロップゾーンを使用する際は表示されるテキストを日本語にしておくと良いです。

下のドロップゾーンは今回×印のsvgにしました。cssで位置を調整するだけでOKです。

ファイルを一つに制限する

「maxFiles」を1にして処理できる数を制限しておきます。

また、「uploadMultiple」も1にして2つ以上のアップロードをできないようにしています。

イベントで「complete」時に使用不可を設定しています。

テスト用なので5秒後に解除していますが、実際には「removedfile」イベントなどで「dropzone.enable()」は行った方が良いです。

「complete」時にdisableとしているので、アップロード中はなにも制限していません。アップロードのイベント中に「disable」を行うとアップロードまで中止されてしまいます。

そこで、「drag」イベントですでに処理中のファイルがある場合に受付を拒否します。(正確にはイベント無効化)

また、ファイルを二つ選択してドラッグできてしまうのも同じようにして受付拒否しています。

2022/08/03追記

ドロップ自体のキャンセルは難しいようです。

codepenの方では記述に誤りがあり、エラーが発生することでドラッグイベントが無効化されていました。

そのため、throwに変更しています。

初期ファイルを設定する

mockFileにはファイルの情報を渡してあげます。

「name」「size」の二つを渡してあげるとホバー時に表示される「ファイル名」「ファイルサイズ」に反映されます。

defaultImageにはファイルパスを渡してください。

(例ではクロスオリジンで引っかかったため、適当な名前を入れています。)

バックエンドからの返り値を使用したい

echo json_encode( [
'id' => $image_id
] );
exit;

画像がアップロードされると、バックエンドから登録した画像IDが返ってくる例です。

fileにはxhr情報が含まれています。その中のresponseを取得してバックエンド側から送られてきたものを読み込んでいます。

バックエンドの実装

input要素のtype=fileと同様に扱えばOKです。

PHPであれば以下URLを参考にしてみてください。

https://www.w3schools.com/php/php_file_upload.asp

私がWordPressで行った一例をご紹介。

  • tmpからuploadsフォルダに移動
  • attachment登録
  • 各種画像サイズの作成

まとめ

各種説明をしたら結構長くなりました。。。

公式のDocument読んで撃沈した人に是非参考にしてもらえればと思います。

javascript得意な人はコードから読んだ方が絶対わかりやすいです。量も少なく非常に読みやすいコードしています。

今回の説明で一切触れませんでしたが、ファイルを分割して送信することも可能です。(chunk)

通常の画像なら必要ないと思いますが、印刷用のファイルであったりとサイズが大きくなる場合は分割して送信すると良いです。

その場合はバックエンド側の処理も通常よりひと手間必要です。

2020 KumaTechLab.