ページ内の画像をワニに変えるボタンを Vue.js でつくってみた

#概要
ちょっと前に、ページ内の画像を全てワニに変えるボタンの話が[ニュース](https://headlines.yahoo.co.jp/hl?a=20180522-00000056-it_nlab-sci)になっていました。

そのサイトでは jQuery が使われていましたが、
Vue.js ならより直感的に作れそうだと思ったので、練習がてら作ってみました。

#デモ

[デモページ](https://masa-shin.bitbucket.io.)
（ワニ画像を集めるのが大変だったので、ねこにしました）

↓のページの画像が‥‥

![無題.png](https://qiita-image-store.s3.amazonaws.com/0/123809/904f9029-e06f-6957-2554-a1c653b22053.png)

緊急ボタンを押すとランダムなねこ画像に変化します。

![無題2.png](https://qiita-image-store.s3.amazonaws.com/0/123809/da9ba515-4a26-11e7-5ea7-f786a69b6496.png)


#実装の考え方

- 元画像のファイル名が入った配列を data につくる

```javascript:src/App.vue
  data () {
    return {
      imagePath: './static/images/',
      imageNames: [
        'dosukebe_1.jpg',
        'dosukebe_2.jpg',
        'dosukebe_3.jpg'
      ],
      pageTitle: '秘密',
      numberOfCatImages: 5, // ねこ画像総数
      loading: true
    }
  },
```

- computed で「元画像のパスの配列」を作る

```javascript:src/App.vue
  computed: {
    imageNamesWithPath: function () {
      return this.imageNames.map((value) => {
        return `${this.imagePath}${value}`
      })
    }
  }
```

- 「パスの配列」の要素を、img タグにバインドする 

```html:src/App.vue
      <div class="flex" id="images">
        <img v-for="image in imageNamesWithPath" :src="image">
      </div>
      <button @click="changeImages()" :disabled="loading">緊急回避</button>
```

- 緊急ボタンを押したときに配列を書き換えれば、画像も書き換わる

```javascript:src/App.vue
methods: {
    changeImages: function () {
      this.imagePath = './static/images/cat/'
      this.imageNames = this.imageNames.map((value) => {
        let randomNumber = this.getRandomNumber(1, this.numberOfCatImages)
        return `cat${randomNumber}.jpg`
      })
      this.pageTitle = 'ねこ'
    },
    getRandomNumber: (min, max) => {
      return Math.floor(Math.random() * (max + 1 - min)) + min
    }
  },
```

#画像のローディングが長い問題

上記だけでも一応機能はするのですが、画像を書き換える際に読み込み時間が発生してしまいます。

それでは重要な局面で間に合わなくなる可能性が生じるため、
以下のように事前に全ねこ画像をキャッシュします。

```javascript:src/App.vue
  created: function(){
    for(let i=1; i <= this.numberOfCatImages; i++) {
      let img = new Image();
      img.src = `./static/images/cat/cat${i}.jpg`; // キャッシュ！
 
      //デモのため、画像読み込み完了後にボタンを有効化する
      if(i === this.numberOfCatImages) {
        img.onload = () => {
          this.loading = false;
        }
      }
    }
  }
```

created に指定された関数は、Vue インスタンスが作成された直後に呼びだされます。

上では画像を順番に読み込んでいき、最後まで読み込み終わったら ”this.loading = false;” で緊急ボタンを有効化しています。

#余談：隠しコマンド

ワニマガジン社のサイトのソースをのぞいていたら、
隠しコマンドがありました。

```javascript:_emergency.js
jQuery(function($) {
	'use strict';

	$.fn.waniEmergency = function(args) {
		var input    = [];
		var konami   = [16, 16, 16];
		var namco    = [38, 38, 38];
		var imgCache = [];
		var config   = $.extend({
			src   : 'src',
			srcset: 'srcset',
			target: '',
		}, args);

		var method = {

			（中略）

			checkCode: function(codeArray, _target) {
				return codeArray.join('-').indexOf(_target.join('-')) >= 0;
			}
		};
 
		（中略）

		$(window).keyup(function(e) {
			input.push(e.keyCode);

			if (method.checkCode(input, konami)) {
				method.push();
			}

			if (method.checkCode(input, namco)) {
				method.pull();
			}
		});
```

Shiftキーを3連続で押すと緊急回避、↑キーを3連続で押すと元に戻るようです。
（コマンド名は konami と namco ）

こういう遊び心はいいですね。