Livewire + Alpine.jsでファイルをドラッグ&ドロップでアップロードする
calendar_today
2022-08-11
insights
views: 1518
thumbnail images

これなに

Livewire + Alpine.jsでファイルをドラッグ&ドロップでアップロードできるようになる。

gifイメージ(開発中)
https://variant3a.com/storage/posts/pictures/9LxHVLjyptMUji6QRUK4ECKtCuO3PrrB9H6QlVox.gif{loading="lazy"}

経緯

Livewireでドラッグ&ドロップ アップロードを実現する方法を模索していた。
調べても全然情報が出てこないので、自分なりにフルスクラッチでやってみたところ、メチャクチャ簡単に実装できたので紹介する。

環境

  • Laravel 9
  • Livewire 2
  • Alpine.js

ソースコード

ソースコード一式はここに置いてある
https://github.com/variant3a/variant3a

コード解説

Livewire PHP側

class Index extends Component
{
    use WithFileUploads;

    public string $title = 'Photos';
    public $files = [];

    public function updatedFiles()
    {
        $this->upload();
    }

    public function render()
    {
        return view('livewire.photo.index', [])
            ->extends('layouts.app', ['title' => $this->title])
            ->section('content');
    }

    public function upload()
    {
        $this->validate([
            'files.*' => 'image|max:20480',
        ]);

        foreach ($this->files as $file) {
            $file->store('photos');
        }
    }
}

一連の流れ

  1. use WithFileUploads をつけておく
  2. public $files = [] で、複数ファイルを格納する変数を用意する
  3. updatedFiles() で、変数 $files が書き換わると実行される
  4. upload() で、 $files の内容を保存する

重要

updatedHoge()

updatedHoge() で、変数 $hoge を監視する。
Livewire 2.x ライフサイクルのフック

blade側

<div class="upload-container"
    x-data="{ droping: false, progress: 0 }">

    <div class="position-absolute top-0 start-0 vw-100 vh-100"
        x-on:drop.prevent="$wire.uploadMultiple(
            'files',
            $event.dataTransfer.files,
            () => {droping = false;progress = 0},
            () => {droping = false;progress = 0},
            e => {progress = e.detail.progress}
        )"
        x-on:dragover.prevent="droping = true"
        x-on:dragleave.prevent="droping = false">

        <div class="position-absolute top-50 start-50 translate-middle">
            <div class="text-center" x-show="droping && !progress">
                Drop Here
            </div>
            <div x-show="progress !== 0">
                <div class="text-center">
                    Uploading...
                </div>
                <div class="progress" style="width: 70vw">
                    <div class="progress-bar progress-bar-striped progress-bar-animated bg-main-500" x-bind:style="{ width: `${progress}%` }">
                    </div>
                </div>
            </div>
        </div>
    </div>
</div>

一連の流れ

  1. x-data で変数初期化
  2. x-on:drop.prevent でファイルをドロップしたときに処理が実行される。
    1. $wire.uploadMultiple() にファイルを投げて、成功時/失敗時/処理状況 の処理を記載する
  3. x-on:dragover.preventx-on:dragleave.prevent で、ドラッグ&ドロップの表示用フラグを切り替えている

重要

$wire.uploadMultiple()

$wire.uploadMultiple() で、Alpine.js側からLivewireに値を渡す。

Livewire 2.x AlpineJS

$wire.uploadMultiple(
    'files', // PHP側の変数名
    $event.dataTransfer.files, // jsのdataTransferと同じ
    () => {droping = false;progress = 0}, // 成功時
    () => {droping = false;progress = 0}, // 失敗時
    e => {progress = e.detail.progress} // 処理状況 プログレス
)
calendar_today
2022-08-11
insights
views: 1518