プロフィール画像をドラッグアンドドロップで変更できるように、その際プレビューできるようにするためのコードメモ。
作るもの
ドラッグアンドドロップで使いたい画像をアップロード・保存前にプレビューで確認できる仕様です。
DBへ保存関係はこの記事では取り扱わず、主にドラッグアンドドロップ・プレビュー周りの内容となっております。
CSSは最低限となっていますので文字とか見切れてますが無視でお願いしますm(__)m
ベースのHTML構造・コード
前にも似たような記事を書いた時に作ったこの画像を再掲。

実際は三層構造のようになっていて、重なり順序も大切です。
<form method="POST" action="" enctype="multipart/form-data">
@csrf
<div class="change-image-wrap">
<input type="file" name="image" class="input-image js-droparea">
<img src="" class="drop-image js-show-image" alt="jsから来た画像">
<img src="{{ $image_url ?? asset('img/noimage.jpg') }}" alt="プロフィール画像" class="show-db-image">
</div>
<input type="submit" value="保存">
</form>
フォームなので@csrfも書いてます。
そしてz-indexで一番下の層になるimgタグですが、こんなコードになっています。
<img src="{{ $image_url ?? asset('img/noimage.jpg') }}" alt="プロフィール画像" class="show-db-image">
このsrc属性に書いてあるコードのみピックアップすると、
$image_url ?? asset(‘img/noimage.jpg’)
のように、??で値が区切ってあります。これはnull合体演算子というものだそうで
$image_url の値がNULLでなければ $image_url を、NULLであれば後半の asset(‘img/noimage.jpg’) を使用。という意味です。
つまり、プロフィール画像を設定していなければデフォルトの画像を、プロフィール画像を登録していればその登録した画像を出力、ということになります。
そもそも$image_urlってどこから来てるの??というと、コントローラーから値を渡しています。
//プロフィール画像表示用アクション
public function show(int $id)
{
$image_url = null;
if (Storage::disk('local')->exists('public/profile_images/' . Auth::id() . '.jpg')) {
$image_url = '/storage/profile_images/'. Auth::id() . '.jpg';
}
return view('users.show', [
'image_url' => $image_url
]);
}
初期設定でNULLを代入しておいて、もしローカルストレージに画像があればその画像までのパスを$image_urlへ代入。という流れです。
最初に代入しておく値はNULLにしてください。falseだとうまく動きませんでした・・・
CSS
Sassで書いています。
やりいたいことのほとんどは、z-indexで重ね順をつけることのみ。
.change-image-wrap {
position: relative;
width: 150px;
height: 150px;
.input-image,
.drop-image,
.show-db-image {
position: absolute;
display: block;
width: 100%;
height: 100%;
}
.input-image {
z-index: 3;
}
.drop-image {
z-index: 1;
}
.show-db-image {
z-index: 0;
}
}
jQuery
ここでやっとjQueryです。jQuery本体は別で読み込んでおいてください。
//drag&dropするエリアのドム
var $dropArea = $('.js-droparea');
//prev画面のドム
var $inputFile = $('.js-show-image');
$dropArea.on('dragover', function(e) {
//余計なイベントをキャンセルする
e.stopPropagation();
e.preventDefault();
$(this).css('border', '3px #ccc dashed');
});
$dropArea.on('dragleave', function(e) {
e.stopPropagation();
e.preventDefault();
$(this).css('border', 'none');
});
//画像情報が入って(changeしたら)きたら
$dropArea.on('change', function(e) {
$(this).css('border', 'none');
// files配列にファイルが入っています
// ファイル情報を取得
var file = this.files[0],
// ファイルを読み込むFileReaderオブジェクトを変数に
fileReader = new FileReader();
// 読み込みが完了した際のイベントハンドラ。imgのsrcにデータをセット
// fileReaderの読み込みが完了した時のイベント
fileReader.onload = function(event) {
// 読み込んだデータをimgに設定
// 最初非表示になってるimgを表示
$inputFile.attr('src', event.target.result).show();
};
// 画像ファイル自体をデータURLとして読み込んでいる(画像のsrcへ挿入)
fileReader.readAsDataURL(file);
});
コメントを書き込んでいるので、順を追ってみてみてください。
最初にドムを取得して変数に代入しているので、取ってくるクラス名を間違えなければそんなにコードをいじらなくてもお使いの環境で使えるのではないかなーと思います!