◆したいこと

  • APIで画像を表示する。(SVGじゃないやつ)
  • APIで画像が取得できなかった時は、指定の画像を表示する。(SVGでもなんでも)
  • APIを2回投げたくない。画像が取得できたのならそれをDataURIの形にしてしまおうと思う。

◆おことわり

以下の成分を含みます。

これから説明するんだけど、どっから説明したもんかわからんから適当に説明する。「わかんね」って人はコメントしてくれ。

◆結論

つかわれるほう

つかうほう

◆勘所

勘所さん!?

「結論」の項のソースを眺めながら確認してくれ。

▼親からURL渡す

今回の例では、「AnyComponent」さんが「ImageComponent」のプロパティ「ImageURL」に向けてURLをバインドしている。

分けてみたけど、無論ひとつのコンポーネントで完結させることもできますね。
あと「v-bind:ImageURL」って書いてるけど「:ImageURL」でいいよ。

▼初期化(mountedメソッド)

  1. とりあえずスピナーを表示
  2. 読み込めるか確認
  3. 読み込めたらその画像
  4. 読み込めなかったらダミー画像

って流れをたどるので、mountedのライフサイクルフックでスピナー画像を設定しておく。

ロード中画像を持ってない人はloading.ioでSVGスピナーを生成しよう。べつにgifでもいいけど。また、loading.ioのスピナーは詰めが甘いから暇な人は容量最適化して遊ぼう。

この例ではwebpackのresolve.aliasでパス指定している。’@’がそれだな。

▼読み込み(getImageUriメソッド)

プロパティ「ImageURL」にURLを受け取った「ImageComponent」くんは、画像をAPI取得する。取得にはaxiosを利用している。

このメソッドはPromiseであるため処理が待たれない。だからロード中画像を表示することが出来る。

APIで画像が取得できた時、responseを加工してDataURIに加工する。取得に失敗したとき、つまりcatchに於いて、差し替えのための画像を読み込む。

(この記事の)旧バージョンでは

btoa(String.fromCharCode(...new Uint8Array(response.data)))

でbase64にしてたんだけど、クソデカ画像くんだとArrayこわれるんでreduceでアレした。

あと、今思ったんだけどSVG取得したらこれbase64にしちゃうから駄目だね!ごめんね!

▼Computedで読み込み。

Computedで変数「uri」を読み込む。

んだけど、typescriptなんでgetアクセサで定義する。

imgタグのsrcにgetterをバインドする。「src」じゃなくて「:src」じゃないとバインドできないから注意。

▼読み込み失敗

二枚目の画像の読み込みが失敗するので、指定した画像が表示される。

読み込み失敗する理由は、CORSによるものだ。
つまり、「https://steadiness-law.jp/」ドメイン以外からの使用を許可していないのだ。詳しくはググろう。

404でもちゃんと動くよ。

動確はしたつもりだけど、動かなかったら教えてくれ。

◆おとくなけいじばん

Vueのバインディングってやつは結構ヤバくて、コンポーネントのプロパティに(ほぼ)直でjsonをバインディングできたりする。

  • フィールドにany型を定義して
  • JSON.parse([jsonな文字列]) を代入して
  • そのまま v-bind=”[フィールド変数]“ することができる。

anyの配列を定義してそこにjson配列をぶち込み、v-forでまわしながらv-bindなんてことも可能だ。型が不安定なのが難点だけど、利便性と天秤にかけた時に利便性が勝っちまう気がする。

◆結論(2回目)

Wifi6が来たらNASを買う(決意)