素のJavaScript（ES6）で画像プレビュー機能を実装する

## はじめに
JavaScriptとFile APIを使い、ユーザーがローカルの画像ファイルを選択し、
選択された画像のプレビューを以下のようにブラウザに表示させる方法をまとめました。
![スクリーンショット 2020-10-29 15.36.32.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665045/edf47397-ec04-dc54-68c7-25eb2e4f0ae2.jpeg)



## ソースコード


**▼HTML**

```HTML
<input type="file" id="input">
<div id="preview"></div>
```

**▼JavaScript**

```js
document.addEventListener('DOMContentLoaded', () => {   // ①
  const input = document.getElementById('input');   // ②
  const preview = document.getElementById('preview');   // ③

  input.addEventListener('change', event => {   // ④
    const file = event.target.files[0];   // ⑤

    if (file.type.match(/image\/*/)) {   // ⑥
      const reader = new FileReader();   // ⑦
      reader.addEventListener('load', event => {   // ⑧
        preview.innerHTML = '<img src="' + event.target.result + '">';   // ⑨
      });
      reader.readAsDataURL(file);   // ⑩
    }
    else {
      alert("画像ファイルを指定してください。");
      input.value = '';   // ⑪
      return false;   // ⑫
    }
  });
});
```

## 解説

以下、JavaScriptの解説をしていきます。

**▼①について**

```js
document.addEventListener('DOMContentLoaded', () => {
```
ここでは、HTMLの読み込みが終わった後に関数が実行されるようにアロー関数を用いて記述しています。

**▼②、③について**

```js
  const input = document.getElementById('input');   // ②
  const preview = document.getElementById('preview');   // ③
```
②ではHTML内のidが`input`の要素を定数`input`に代入し、
③ではidが`preview`の要素を定数`preview`に代入しています。

**▼④について**

```js
input.addEventListener("change", event => {
```
ここでは、②で定義した`input`で`change`イベントが発生した際に、
`event`の中の関数を実行するように記述しています。

`change`イベントとは、`<input>`要素などにおいて、
ユーザーにより要素の値が変更されたときに発生するイベントです。 

つまり、上記のように記述することで、
ユーザーが画像を選択したときにイベントが実行されるようにしています。

さらに、ここでは`event`をアロー関数の引数として渡すことで、
`{}`内でイベント発生時の情報を利用できるようにしています。

アロー関数は引数が0か2つ以上の場合は括弧`()`が必要になりますが、
引数が1つの場合は括弧を省略することができます。


**▼⑤について**

```js
const file = event.target.files[0];
```
選択されたファイルを`file`に代入しています。

`event.target`と記述することで、イベントの発生源であるオブジェクトを取得することができます。
イベントで取得した要素の値を使いたいときは、このように`target`属性を指定します。

今回のようにHTMLで`input`要素のタイプを`file`と指定している場合は、
`FileList`というオブジェクトの中に選択されたファイルが格納され、
`event.target.files`とすることでそのオブジェクトを取得できます。

また、`FileList`は配列となっているため、1枚取得する場合は`[0]`を加えます。

`console.log(event);`などと記述することで、`event`の中身の構造が理解しやすくなると思います。
以下、`event.target.files`の中身です。
![スクリーンショット 2020-10-29 16.53.03.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/665045/9b310f26-66f8-09cb-e1c8-2498a76c3aa9.jpeg)


**▼⑥について**

```js
if (file.type.match(/image\/*/)) {
```
ここでは、選択されたファイルの形式が画像である場合のことをif文で記述しています。

`file.type`と書くことで、ファイルの形式を取得できます。
⑤の解説で載せた`event.target.files`の中身の画像を見ると、
ファイルのオブジェクトの中に`type: "image/jpeg"`と書かれているのがわかりますね。

`match(/image\/*/)`では、`file.type`で取得した値の文字列が
"image/○○"となっているかを正規表現で確認しています。


**▼⑦について**

```js
const reader = new FileReader();
```
`FileReader`というファイルを読み込むオブジェクトを新しく作成し、定数`reader`に代入しています。


**▼⑧〜⑩について**

```js
reader.addEventListener('load', event => {   // ⑧
  preview.innerHTML = '<img src="' + event.target.result + '">';   // ⑨
});
reader.readAsDataURL(file);   // ⑩
```

⑧では、ファイルの読み込みが完了した時に発生するイベントを定義しています。

一旦⑨を飛ばして⑩の解説をすると、⑩ではファイルを読み込んでいます。
`readAsDataURL`は、ファイルを読み込み、データをbase64という形式のURLに変換するメソッドです。
ここでは⑤で定義した`file`を読み込み、変換しています。
このメソッドではファイルの読み込みが終わると、`result`属性に変換済みのURLを格納します。

また、⑩でファイルの読み込みが終わると`reader`の`load`イベントが発生し、
⑧と⑨で定義した関数が呼ばれます。

⑨では、③で定義した`preview`の要素の中身に選択した画像を挿入しています。
右辺で`img`要素の`src`属性に、⑩で変換されたデータのURLを入れています。


**▼⑪、⑫について**

```js
else {
  alert("画像ファイルを指定してください。");
  input.value = '';   // ⑪
  return false;   // ⑫
}
```
ここでは、ユーザーが選択したファイルが画像ではなかった場合の処理を記述しています。

⑪では、②で定義した`input`要素の値を空にしています。
また、⑫で画像以外が選択された場合は処理が止まるように記述しています。

## 参考にしたサイト・動画
[Web アプリケーションからのファイルの使用](https://developer.mozilla.org/ja/docs/Web/API/File/Using_files_from_web_applications)
[FileAPIのreadAsDataURLメソッドでローカルの画像ファイルをブラウザに表示させる](https://designsupply-web.com/media/knowledgeside/5779/)
[画像をアップロード＆プレビューしよう【わかりすぎて怖いJavaScript入門】](https://www.youtube.com/watch?v=7WmkYEZc3as&list=PLX8Rsrpnn3IVvcPCZTixO7Pf5lAGoyNOA&index=8)