dropzone.js + Laravel8で画像アップロード機能を実装する
何ができる?
こんな感じで複数画像アップロード+プレビューを簡単に実装できる
ちなみにデフォルトでは、画像はドロップした瞬間にサーバー側にアップロードされます
(autoProcessQueueをfalseに設定することで無効にすることは可能)
フロント(表示)側の実装方法
準備
公式サイトによるとnpm,yarnもしくはスタンドアローン方式にどちらかが選べる
今回は簡単なスタンドアローン方式で
<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" />
html(blade)ファイルのhead内に記載する
表示
htmlで書く場合
<form action="/file-upload" class="dropzone" id="my-awesome-dropzone"></form>
ファサードを使う場合
{{Form::open(['url' =>'/file', 'files' => true, 'class' => 'dropzone', 'id' => 'my-awesome-dropzone'])}}
{{Form::close()}}
以上。
これだけでOK
注意点
このformは画像アップロード専用なので要注意
他にも送信したい項目がある場合は別フォームを用意する
<!-- 画像アプロード用 -->
{{Form::open(['url' =>'/file', 'files' => true, 'class' => 'dropzone', 'id' => 'my-awesome-dropzone'])}}
{{Form::close()}}
<!-- 入力項目送信用 -->
{{Form::open(['url' =>'/input', 'files' => false])}}
{{ Form::select('hoge', hoge, null) }}
{{Form::close()}}
オプション
かなり色々なオプションが指定できる
また、各種メッセージがデフォルトでは英語になってるので日本語にする必要もありそう。
<script>
const dropzone = new Dropzone( '#my-awesome-dropzone', {
maxFilesize: 5, // 最大ファイズサイズ(MB)
maxFiles: 7, // 最大ファイルアップロード数
timeout: 2000, // タイムアウト(ms)
addRemoveLinks: true, // 削除用リンクを追加するか
acceptedFiles: '.jpeg,.jpg,.png,.gif', // 許容するファイルタイプ
dictDefaultMessage: 'ファイルをドラッグ&ドロップしてね。', // アップロードエリアの表示メッセージ
dictInvalidFileType: 'このファイルタイプはサポートされてないよ。', // サポート外の時に表示するメッセージ
dictMaxFilesExceeded: 'これ以上アップロードできないよ。', // 最大アップロード数を超えたときのメッセージ
}).on("success", function(file, serverResponse){
// アップロードが成功した時にここにくる
}).on("removedfile", function(file){
// ファイルを削除した時にここにくる
// サーバーからファイルを削除するajaxなどを実装する
});
</script>
サーバーサイドの実装
<!-- 画像アプロード用 -->
<form action="{{route('dropzone.store')}}" method="post" name="file" files="true" enctype="multipart/form-data" class="dropzone">
先ほどのHTMLのaction部分を修正
(dropzoneからアップロードされた画像を取得するためのURLを設定)
use App\Http\Controllers\DropZoneController;
Route::post('dropzone/store', [DropZoneController::class, 'dropzoneStore'])->name('dropzone.store');
ルーティングファイルに、上記のactionで指定したrouteを設定
class DropZoneController extends Controller
{
public function dropzoneStore(Request $request)
{
$image = $request->file('file');
$imageName = time() . '.' . $image->extension();
$image->move(public_path('uploads'), $imageName);
return response()->json(['success' => $imageName]);
}
}
フロント側から送信されたファイルを受け取ってドキュメントルートのuploadsディレクトリに保存する例
編集画面で初期イメージを設定する
編集フォームで既に登録済みの画像をデフォルト表示する方法
<script>
const dropzone = new Dropzone( '#my-dropzone', {
maxFilesize: 5,
maxFiles: 10,
init : function() {
let mockFile = { name: "filename", size: 123 };
this.displayExistingFile(mockFile, "https://hoge.com/storage/uploads/h.jpg");
// maxFilesオプションを指定してる場合はこれを指定する
this.options.maxFiles = this.options.maxFiles - 1;
}
参考:https://github.com/enyo/dropzone/wiki/FAQ#how-to-show-files-already-stored-on-server
ここまで作って気がついたんですが、編集フォームでアップロード画像を更新する場合は
autoProcessQueue: false
を使ってサブミット時に画像を送信するように変更しないとダメそう
なぜなら、編集画面でサブミットボタンを押す前に画像を更新して離脱されると、ユーザは更新してるつもりがなくてもサーバから画像は削除されてり変更されてしまうから。
あとがき
このようにDropzoneを使うと非常に簡単にファイルのアップロードが実装できます
ただし、ユーザがファイルを削除した時に、サーバー側でアップロード済みの画像を削除したりするのは開発者側で実装しないといけません
こんな感じで、細かく見るとあまり痒いところに手は届いてない感がありますが、「それが面倒なら有料版のPlusを使ってください」という意味なのだと思います
ディスカッション
コメント一覧
まだ、コメントがありません
新たにPostされたDocs
: ツール関連
キーボードを銀軸から赤軸に買い替えた話
約3年半前、仕事で使うキーボードとしてARCHISS ProgresTouchの ...: スマホ
楽天モバイルがおすすめできない人の特徴とは?
楽天モバイルの最強プランをおすすめできない人の特徴を簡単にまとめてみました また ...: システム開発
なぜスクラムがつらいのか?開発現場が疲弊するのか?スクラムに対する違和感と共に原因を考えてみた
今ではどこの開発現場に行っても、やれスクラムスクラムと、まるでスクラムでもやって ...: Laravel
1つのテーブルを複数のテーブルと結合したい【Laravel10】
1つのテーブルを2つの異なるテーブルに対して結合したいケースがあったのでLara ...: Laravel
Laravelで複数画像アップロード時のvalidateを指定【Laravel10】
jQuery - Image Uploaderを使って、フォームから複数の画像を ...HashMap
created_by
はやぴ
Web/アプリ開発エンジニア
Sierにてお堅いB向けのソフトウェア開発を経て、現在はC向けのWebやアプリを中心に開発しています。
Utilities