Laravel8 jQuery 画像動的表示

## 初めに
この記事では、画像選択時にその場で選択した画像を表示させる方法をご紹介します！

[![Image from Gyazo](https://i.gyazo.com/58c381c1bc1418ab895dd66ad810b352.gif)](https://gyazo.com/58c381c1bc1418ab895dd66ad810b352)

## 実装
今回は以下のように実装してみました。
CSSはTailwindCSSを使用してます。

・add.blade.php（画像選択のビュー）

```php
<div class="flex justify-center md:px-20 xl:px-20">
    <label class="block px-12 py-2 rounded-md bg-gray-300">
        <p class="text-center">画像を選択</p>
        <input id="img_upload" type="file" accept="image/*" name="image" value="{{old('image')}}" class="hidden -ml-12" onchange=" previewImage(this)">
        @error('image')
        <p class="w-44 text-red-500 text-sm">{{$message}}</p>
        @enderror
    </label>
</div>

<div class="flex justify-center">
    <label class="block w-44">
        <img id="preview" class="h-48 w-full" src="https://zaikokanri.s3.ap-northeast-1.amazonaws.com/SQBzGcvgGvOftMYGWG85i2DBuXaONl6FbiW9uwoA.jpg">
    </label>

    <script>
        function previewImage(obj) {
            var fileReader = new FileReader(); 
            fileReader.onload = (function() {
                document.getElementById('preview').src = fileReader.result;
            });
            fileReader.readAsDataURL(obj.files[0]);
        }
    </script>
</div>
```

・app.blade.php
add.blade.phpは親元であるapp.blade.phpを継承している構成になっていますが、一様app.blade.phpの<head>部分は以下のような感じになってます。

ここに関しては今回のjQuery導入に合わせて何か読み込んだりといったことは特にしていないです。

```php
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="csrf-token" content="{{ csrf_token() }}">

    <title>@yield('title')</title>

    <!-- Fonts -->
    <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700&display=swap">

    <!-- Styles -->
    <link rel="stylesheet" href="{{ mix('css/app.css') }}">

    @livewireStyles

    <!-- Scripts -->
    <script src="{{ mix('js/app.js') }}" defer></script>

</head>
```

## jQuery部分の説明

```js
<script>
    function previewImage(obj) {
        var fileReader = new FileReader();
        fileReader.onload = (function() {
        document.getElementById('preview').src = fileReader.result;
    });
            fileReader.readAsDataURL(obj.files[0]);
        }

        $(function() {
            $(document).on('change', '#receipt', function() {
                $('#preview').addClass('img-thumbnail');
            });
        });
</script>
```

・`var fileReader = new FileReader();`
FileReaderオブジェクトでユーザーのコンピュータに保存されているファイルの内容を非同期に読み取る。
それをvarで定義したfileReader変数に格納。

https://developer.mozilla.org/ja/docs/Web/API/FileReader

・`document.getElementById('preview').src = fileReader.result;`
・`document.getElementById('preview').src`
画像選択ボタン部分で指定した`id=preview`かつ`画像要素を特定`。

https://www.web-labo.jp/archives/2493

・`fileReader.result;` 
読み込んだファイルの内容を返す。また、こちらはデータの読み取り操作が完了した後でしかファイルの内容を返しません。読み取りができてない場合はnullとなります。

https://developer.mozilla.org/ja/docs/Web/API/FileReader/result

・`fileReader.readAsDataURL(obj.files[0]);` 
ファイルのデータを表す`base64`エンコーディングされた`data:URL`の文字列を格納。

・`readAsDataURLメソッド` 
指定されたfile型の内容を読み込む。
読み込み操作が終了すると`readyStateがDONEとなりloadendが発生`。このとき、result属性には`ファイルのデータを表すbase64エンコーディングされたdata:URLの文字列`が格納される。

・`readState` 
XMLHttpRequestのプロパティで、通信状態を表す数値を返す。

・`DONE` 
`成功・失敗に関わらず通信を終了した状態。`

https://lab.syncer.jp/Web/API_Interface/Reference/IDL/XMLHttpRequest/readyState/#:~:text=readyState%E3%81%AF%E3%80%81XMLHttpRequest%E3%81%AE%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3,%E3%81%AB%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82

・`load`
loadendイベントは、リクエストが正常に完了した場合`afterload`または失敗した場合`afterabort`または`error`が発生。

https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/loadend_event

・`base64`
64進数を意味する言葉で、すべてのデータをアルファベット`a〜z, A〜Z`と数字`0〜9`、一部の記号`+,/`の64文字で表すエンコード方式。
データ長を揃えるためにパディング（データを一定の長さに整形するため前後に挿入される無意味なデータ）として`末尾に記号の＝`を使用。

https://qiita.com/PlanetMeron/items/2905e2d0aa7fe46a36d4

## おまけ
下記のようにしてあげると画像周りに角丸の枠線を付け加えることができます！

```js
$(function() {
 $(document).on('change', '#receipt', function() {
     $('#preview').addClass('img-thumbnail');
 });
});
```

・`$(document).on('change', '#img_upload', function(){}`
changeイベントが発生したとき、function{}に書いた処理を実行する。

・`change`
フォーム(input要素)や選択メニュー(select要素)、テキストエリア(textarea要素)にてユーザーの操作によって値が変更されたときに発生するイベント。

https://developer.mozilla.org/ja/docs/Web/API/HTMLElement/change_event

https://www.sejuku.net/blog/38774

・`$('#preview').addClass('img-thumbnail');`
`#previewに対して``img-thumbnailクラス属性を追加`。

https://www.sejuku.net/blog/47314

・`img-thumbnailクラス`
bootstrapのクラスで、画像の周りに角丸の枠線が追加される。

https://corecolors.net/bootstrap8/