Vue.jsで作るビンゴアプリ！

# はじめに
ども、最近、[#週一アプリチャレンジ](https://twitter.com/search?q=#週一アプリチャレンジ)というものをやり始めた人です。

毎週土曜日にアプリを作る配信をする企画です。
今回は、その二回目に作ったビンゴアプリの話をします。

---

アプリ↓

https://bingo.zscode.net


リポジトリ↓

https://github.com/sas08/Weekly-App/tree/001-Bingo

# 何を作ったの？
ビンゴアプリです。
1～nまでのランダムな整数を表示してくれるやつです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/2777223f-0060-22b9-f429-2f7d71e5ae80.png)

デザイン性は皆無ですが、なかなかいいものができたと思ってます。

# 機能
ここからは、このビンゴアプリが持つ機能を紹介していきます。

## 数字が高速で切り替わる
ビンゴのメイン画面に飛ぶと、三つのボタンがあると思います。
その一番上のボタンを押すと、ルーレットが開始します。

```javascript:ここで使ってる変数
this.numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 1~nまでの数列
this.bingoNumber = 0 // 上に表示してる数字
this.alreadyList = [] // 既出の数字を格納
```
```javascript:
const loadBingo = setInterval(() => {
  this.bingoNumber = this.numList[Math.floor(Math.random() * this.numList.length)]
}, 100)
setTimeout(() => {
  clearInterval(loadBingo)
  const notYetList = this.numList.filter(i => this.alreadyList.indexOf(i) === -1)
  this.bingoNumber = notYetList[Math.floor(Math.random() * notYetList.length)]
}, 1500)
```

`setInterval()`は、一定間隔で何度も処理をする関数です。
これをしたことで、100ミリ秒に一度、1-10までの数列からランダムで数字が選ばれるようになっています。
この`setInterval()`は、`clearInterval()`を使うことで止めることができます。
ここでは、`setTimeout()`という関数を使って、1500ミリ秒待ってから1-10の中から数字を選ぶ処理を止めています。

下から三行目の`notYetList`は、`this.numList`と`this.alreadyList`を使って、まだ出ていない数字のリストの作成を行っています。
上で表示している数字はこの、未出リストから取り出しているので、重複なく数字を取り出すことができています。

## 選ばれた数字に色がつく
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/a4fdba50-b0ec-d5ad-ce64-aa1cecf8e53c.png)
選ばれた数字には色が付きます。
```javascript
this.numList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // 1~nまでの数列
this.alreadyList = [2, 8] // 既出の数字を格納
```
```vuejs
<v-row class="text-center" justify="center">
  <v-col
    cols="12"
    sm="1"
    v-for="num in numList"
    :key="num"
  >
    <v-chip
      v-if="alreadyList.includes(num)"
      v-text="num"
      color="light-blue lighten-1"
    />
    <v-chip v-else v-text="num" />
  </v-col>
</v-row>
```
`v-col`についている`v-for`で1-10までの数列を回しています。
ちなみに、`v-for`が`v-chip`ではなく、`v-col`についているのは、`v-row`につけた`justify`が`v-chip`に適用されないからです。
（`v-for`と`v-else`の併用が推奨されていないのも理由の一つ）

```
v-if="alreadyList.includes(num)"
```
これで、`this.alreadyList`に`num`(numListの中の数字)があるかを確認しています。
もし、含まれていた場合は、`color`プロパティが与えられた、青色チップが表示されます。
そうでなかった場合は、`v-else`がついている、色なしチップが表示されます。

## JWTを使った状態保存
SAVEボタンを押すと、こんなダイアログが表示されると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/4e434baf-195f-638b-fdf8-5366434a53c3.png)
技術的に、クリップボードに保存する機能をつけれなかったので、自分でコピーするようになっていますが、これを使うことで、状態の保存/復元ができるようになっています。

状態の復元は、最初のページの下のボタン、`LOAD`と書かれたボタンを押して飛ばされるページで使用できます。

試しに、このトークンを使ってみてください。
```
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmaXJzdE51bWJlciI6MSwibGFzdE51bWJlciI6IjMwIiwiYWxyZWFkeUxpc3QiOlsxMyw2LDMwLDExXSwiaWF0IjoxNjQ1ODY3NzkyfQ.qpPZmxuW8fXrFgl2S9b56zbdjpepqOFlJ3L6Ph8kbSg
```
多分、1-30の6,11,13,30が埋まっているルーレットが読み込まれると思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974385/f7c36b32-0915-da54-0747-200e183aef77.png)
**ならなかったら、コメントかDMください**

---

さて、内部構造の説明をしていきましょう。

https://jwt.io/libraries?language=Node.js

このサイトを見るとわかると思いますが、JWTを使うことができるnode.jsライブラリは三つあります。（ほかにもあるけど、公式が認めてる(?)ライブラリがこの三つだと思う...）
今回は、その中でも最もスターが多かった

https://github.com/auth0/node-jsonwebtoken

を使うことにしました。

とりあえず、インストールしましょう。
```:console
npm install jsonwebtoken
```

使い方を紹介します。
といっても、公式のREADMEに書いてあることの復唱になりますが((
```javascript
const jwt = require('jsonwebtoken');
const token = jwt.sign({ foo: 'bar' }, 'shhhhh')
```
この、`'shhhhh'`というやつは、JWTの***シークレット***と呼ばれるやつで、これをもとにJWTのエンコード/デコードが行われます。
これが漏れると、セキュリティ上相当危ないそうなので、`.env`で保存するなど、注意しましょう

さて、このコードでエンコードができます。
`{ foo: 'bar' }`という部分は、JWTから取ることができる内容の部分です。
ここには、基本、なんでも入れていい...はず((

公式の資料では、ここに、ユーザー名やアドミンかどうかのt/fが格納されてました。
僕のビンゴアプリでは、最初の数と最後の数、あと、既出リストを格納しています。

---

次にデコードの話ですが、これも超簡単で、
```javascript
const decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar
```
たったのこれだけ！

まとめると、

```javascript
const jwt = require('jsonwebtoken');
const token = jwt.sign({ foo: 'bar' }, 'shhhhh')

const decoded = jwt.verify(token, 'shhhhh');
console.log(decoded.foo) // bar
```
たったの四行だけで、エンコード/デコードの実装ができてしまいます！
すごいですね。
最初見たときは驚きました。

### ちなみに、
上のロード機能でデコードした情報はどうやって移行しているのかというと、`vuex`を使っています。

https://qiita.com/kouki-iwahara/items/1a75daaa93657b0b56d7

https://qiita.com/fruitriin/items/42b0ebc5f8a524a0ae17

Vuexに関しては、この二つの記事がとてもわかりやすいです。
ぜひ

# さいごに
[#週一アプリチャレンジ](https://twitter.com/search?q=#週一アプリチャレンジ)という、毎週一個アプリ出す企画始めました。

軽いやつに関しては記事化までいかないと思いますが、
重たいものに関しては、今回みたいに記事にします。

どうぞ、よろしくお願いします。

じゃ、
ﾉｼ