Vue.jsでの画像指定方法を間違ってたので、振り返る

先日個人的にVue.jsで開発してた時に、Vue.jsの`background-image`指定でハマって推定１day溶かしてしまったので、
悲しい思い出とともに、Vue.jsでの画像指定方法（imgタグとbackground-imageでの指定）を振り返ります

※ ハマった件に関しては後日30分で解決しました。


# TL;DR
- 画像って`./static`と`./assets`どっちに置くの？
- `./assets`に置いた画像の振る舞いが、思ってんのと違った

とりあえずcodesandoboxにサンプル作ったので、読書辛い人はこっちだけで十分そう。
[![Edit vue image show pattern](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/jvxpp41yxv)


# はじめに
## 通常の画像指定方法
いちおう一般的な画像表示だとだいたい以下の方法が考えられますね

#### imgタグを使用
```html
<img src="./images/image.png" />
```

#### css background-imageで指定
```html
<!--
1. 別ファイルもしくはstyleタグからstyle当てる
-->
<style>
  .bg{
    background-image: url("./images/image.png")
  }
</style>
<div class="bg" />

<!--
2. style属性を追加しインラインでstyle当てる
-->
<div style="background-image: url('./images/image.png');" />
```
#### canvasで`ctx.drawImage(image, dx, dy)` する
※ 今回は考慮しないので省略


# ここから本題

通常の指定方法に加えて、Vue.jsではimageのpathが固定でない場合（apiで取得や、propsで渡されるなど）があるので、ちょい増えます
あとcanvasに関しては、今回めんどいので説明省きます


## Vue.jsでの画像指定考慮する点
Vue.jsで画像指定する時に考慮するポイントはとりあえずこんな感じでしょう

+ html要因
  - imgタグを使用する
  - css の`background-image`で指定する
     * classなどでstyle当てる
     * div要素などにstyle属性を追加しインラインでstyle当てる
- 画像の置き場所
  - `./assets`ディレクトリ
  - `./static`ディレクトリ
  - プロジェクト外: 外部URLのものを使用（APIで画像取得したりする場合）
- pathの 変数 or 定数
  - 定数: いつも通り。楽チン
  - 変数: レンダリング時やイベント時にpathが決定する。(styleタグ内では使用できないみたい)

なかなか多いぞ？

単純計算で　`3 * 3 * 2 = 18 `。 18通り。
ただ一部組み合わせ的にできないものもあるので、少し減りますね。

### 考慮しないケース
styleタグ内にvueの変数使用できないみたいなので、 `styleタグ x 変数path`のケースは考慮しません。
あと、一旦プロジェクト外の画像を使用するケースは保留しときます。


## Vue.jsでの画像指定方法

前項の考慮する点から、サンプルを作っていきます。
画像の置き場所をベースに、上記考慮点を元にしてパターンを作っていきます。

- 画像の置き場所
 + **`./assets`に画像配置**
 + **`./static`に画像配置**
- 考慮点
 - 1-1. imgタグに指定。
 - 1-2. imgタグに指定。変数使用
 - 2. css classで`background-image`指定
 - 3-2. css inlineStyleで`background-image`指定
 - 3-1. css inlineStyleで`background-image`指定。変数使用

（表示されないパターンもどんどん書いていきます。）
codesandoboxにサンプル上げてるんで、こちらでみて欲しい...
[![Edit vue image show pattern](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/jvxpp41yxv)

以下しばらく、codesandoboxのサンプルの繰り返しなるので、飛ばしても良いです。
一応変数として使用する画像はscript部分にこんな感じで書いておきます

```vue
<script>
import AssetsImage from "@/assets/img-assets.png";
// import AssetsImage from "../assets/img-assets.png"; // ← こっち記述でも良い！
export default {
  data() {
    return {
      assetsImage: AssetsImage,
      assetsImage_NG: "../assets/img-assets.png",
      staticImage: "/img-static.png"
    };
  }
};
</script>
```


### `./assets`に画像配置
```vuejs
# assets-1-1: imgタグに指定。
<img class="img" src="../assets/img-assets.png" width="100" />
<!--
  - 表示される。（普通慣れ親しんだ書き方....
  -->

# assets-1-2: imgタグに指定。変数使用
<img class="img" :src="assetsImage" width="100" />
<!-- こっちはダメでした↓ -->
<img class="img" :src="assetsImage_NG" width="100" />
<!-- 
  - 変数でpathっていうか画像データ渡してる...のですね
  - ちなみに変数にassets配下のパス突っ込む場合は表示されない。
  -->

# assets-2: css classで background-image指定
<div class="bg bg-assets"></div>
<style>
.bg-assets {
  background-image: url("../assets/img-assets.png");
}
</style>
<!--
  - まあ表示されない
  -->


# assets-3-1: css inlineStyleで background-image指定
<div
  class="bg"
  :style="{ 'background-image': 'url(../assets/img-assets.png)' }"
/>
<!--
  - 出ない。（上の流れから出ないのはわかっていたよ...
  - これで、いけると思って１日溶かした...
  --> 

# assets-3-2:　css inlineStyleで background-image指定。変数使用
<div
  class="bg"
  :style="{ 'background-image': 'url(' + assetsImage + ')' }"
/>
<!-- こっちはダメでした↓ -->
<div
  class="bg"
  :style="{ 'background-image': 'url(' + assetsImage_NG + ')' }"
/>
<!--
  - assetsImage は表示される！
  -->
```

### `./static`に画像配置

```vuejs

# static-1-1: imgタグに指定。
<img class="img" src="/img-static.png" width="100" />
<!--
  - 当たり前のように表示される
  - static配下のファイルはプロジェクト配下に移動されるみたいですね。
  -->

# static-1-2: imgタグに指定。変数使用
<img class="img" :src="imgStatic" width="100" />
<!--
  - 表示される。
  -->

# static-2: css classで background-image指定
<div class="bg bg-static"></div>
<style>
.bg-static {
  background-image: url("/img-static.png");
}
</style>
<!--
  - 問題なく表示！
  -->

# static-3-2:　css inlineStyleで background-image指定
<div
　　class="bg"
　　:style="{ 'background-image': 'url(/img-static.png)' }"
/>
<!--
  - こちらも全然出るぜ！
  -->

# static-3-1: css inlineStyleで background-image指定。変数使用
<div
  class="bg"
  :style="{ 'background-image': 'url('+staticImage+')' }"
/>
<!--
  - 表示される。
  - `./static`でやったやつ全部表示されちゃった
  -->
```

## 振り返り

というわけで、`./assets`と`./static`配下に置いた画像ではだいぶ書き方が違うのだなってことがわかりました。

#### `./assets`配下の画像
`./assets`に置いている画像ファイルは画像ファイルとして参照してるのではなく、
base64にエンコードされて、src="hoge"やurl="hoge"のところに出力してるみたいです。（参考：[アセット URL ハンドリング · vue-loader](https://vue-loader-v14.vuejs.org/ja/configurations/asset-url.html)）
つまり、キャッシュとかは見込めないですね...

#### `./static`配下の画像
逆に`./static`に置いてる画像ファイルは、プロジェクトルートに持ってってくれるので、
`/{fileName}`で簡単に呼べますね。
キャッシュも効きますね。

要は、`./assets`ファイルの扱いがイレギュラーだったということなので、外部のURLの場合も`./static`配下に置いてる画像と同じような扱いでいけると思います。！


あれ？ `./assets`に画像を置くタイミングはいつになるのだ...?　教えて詳しい人


# 最後に

ちなみに、assetsに置いたimageをbackground指定しようとして１日溶かしました！

まあ、全ての元凶は
**staticフォルダがあることに気がつかなかったこと** と
**`vue-cli`のhelloWorldでassets配下の画像を使用している罠** のためでした。

そりゃあ、少し考えれば、少しドキュメント見ればわかるけど、
何も考えていなかったためまんまと「画像はassets内ね！おk！」となります。罠にハマりました。




それでは良いVue lifeを！