合言葉自動生成ツールを作ろう【JavaScript初心者】

初心者の練習として作ってみてください。
勝手に真似したり、改変したりしてGitHub pagesに挙げてもOKです！

![kansei.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2377776/68c493a2-3fe1-e912-3191-3ea78a486d9b.png)

▼完成ページはこちら▼
https://fuuchin.github.io/Aikotobar/

▼ソースコードはこちら▼
https://github.com/fuuchin/Aikotobar/tree/gh-pages

※完成ページは、言葉が5つ合わさった合言葉となっておりますが、この記事では、3つの言葉を組み合わせた合言葉を作ります。

## 前提条件
- `Visual Studio code`がインストールされていること
- `Google Chrome`がインストールされていること

## 手順1:ファイルの作成

3つのファイルをVScodeで**同じフォルダ内に**作ります。
- `index.html`
- `aikotobar.js`
- `style.css`

また、`index.html`を作成したら、`!`と入力し、`Tab`キーを押してから、このように編集しましょう。
```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Aikotobar</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <h1>Aikotobar</h1>
  <p>合言葉を自動生成してくれるアプリです</p>
  <script src="./aikotobar.js"></script>
</body>
</html>
```

`head`内の`link`タグでは`CSS`を読み込み、
`body`の最後の`script`タグでは`JavaScript`を読み込んでいます。

## 手順2:合言葉材料を準備

最初にあった画像のように、自動生成する合言葉はこのように3つの部分に分けられます。
（どんなで）+（どんな）+（何）
例：（助けを求める）+（悪賢い）+（木箱）

なので、1つ目の言葉は1つ目の言葉で、
2つ目は2つ目で、3つ目は3つ目での、3つの配列を準備すればいいのです。

その後の手順3で、それぞれの配列からランダムに取り出し、ランダムな合言葉を生成します。

JavaScriptをこのように編集しましょう。

```javascript:aikotobar.js
'use strict';

const firstWords = ['夜の', 'ただただ', '終わりを告げる', '秋を彩る', '声が大きい', '先のとがった', '不老不死の', '黒き疾風の', 'こちらを見る', '大昔の', 'バズった', 'チリとなった', '空前絶後の', '難しく考えすぎる', 'なぜか', '持ち手のない', '悟りを開く', '暗闇に包まれた', '絶体絶命の', '嬉しそうな', '投げられた', 'ぶん投げられた', '最初で最後の', '最小の', '常識外れの', '世界に一つだけの', '奥が深い', '変に', '助けを求める', '虹色の'];
const secondWords = ['最強の', '惨めな', '考える', '始まりの', '最大の', '美しい', '白い', 'とても小さな', '灰色の', '剝がれた', '盗られた', '幼い', '悪賢い', 'ゴム製の', '最高な', '汚れた', '縮んだ', '曲がった', 'おかしい', '悟りを開く', '折れた', 'ヤバい', '勇者の', '巨大な', '挟まれた', '抜け出せない', '六千円する', '永遠の', '数学好きな', '百年後の', '薄い', '緑色の', '瑠璃色の', '謎の', 'うるさい', 'かわいそうな', '笑顔の', '怒った', '悲しみの', 'おもしろい'];
const thirdWords = ['不死鳥', '紅葉', '親友', 'ウグイス', '防寒着', '葉脈', '万年筆', '羊皮紙', '石ころ', '世界', 'ポスター', '財布', '幼稚園児', '大人', '木', 'クジャク', '退会ボタン', 'ピンポン玉', '宇宙', 'ロケット', '神', 'カッターナイフ', '映画', '米粒', '話', 'サル', 'ゾウ', 'レモン', 'ペット', '惑星', '定規', '英雄', '木箱', '鉄橋', '目覚まし時計', '学校', '病院', 'カレンダー', '鉛筆削り器', 'スプーン', 'ハンドル', 'ゴルフボール', '板', '浮き輪', 'ポット', '蛍光灯', '茶柱', '岩', '剣', '孫の手', '生卵', 'ぬいぐるみ', 'ギャグ', 'マウスポインタ', '椅子', 'カーテン', 'コンサート', 'アプリ', 'スマホ', '時計'];
```

ちなみに、任意で言葉を配列に追加しても良いです。

## 手順3:合言葉作成機能の開発

それぞれの配列からランダムに言葉を取り出し、それをつなげることで、ランダムに合言葉を作成できます。
例えば、`firstWords`の配列からランダムに値を取り出すには、
```javascript
firstWords[Math.floor(Math.random() * firstWords.length)]
```
で、できますが、同じことを3つの配列でするのは面倒なので、関数化しましょう。

```diff_javascript:aikotobar.js
'use strict';

+function arrayRandom(arr) {
+  return arr[Math.floor(Math.random() * arr.length)];
+}

const firstWords = ['夜の', 'ただただ', ....]
```
`+`の行を追加してください。
ちなみに、アロー関数などを使ってもう少し楽に書くと、こうなります。
```javascript
const arrayRandom = arr => arr[Math.floor(Math.random() * arr.length)];
```
引数が1つだけなので、引数のかっこを外せて、
処理が1つだけなので、波かっこと`return`も省略できるのです。

これで、ランダムに値を取り出せられるようになったので、それをつなげてコンソールに表示しましょう。
`+`の行を追加してください。

```diff_javascript:aikotobar.js
'use strict';

const arrayRandom = arr => arr[Math.floor(Math.random() * arr.length)];

const firstWords = ['夜の', ....];
const secondWords = ['最強の', ....];
const thirdWords = ['不死鳥', ....];

+console.log(arrayRandom(firstWords) + arrayRandom(secondWords) + arrayRandom(thirdWords));
```

ファイルを保存して、`index.html`を`Chrome`で表示させましょう。
そして、デベロッパーツールの`Console`を開きましょう。
`Windows`なら、`Ctrl` + `Shift` + `I`
`Mac`なら、`Command` + `Option` + `I`

ランダムな合言葉が表示されましたか？

## 手順4:合言葉とその数を表示

合言葉を`HTML`に表示しようと思うと、`HTML`にそのためのタグが必要になります。
`index.html`をこのように編集してください。
```diff_html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
...
</head>
<body>
  <h1>Aikotobar</h1>
  <p>合言葉を自動生成してくれるアプリです</p>
+  <p>Aikotobarでは <sapn id="kinds"></sapn> 通りの合言葉を作成できます</p>
+  <p><button id="btn">作成</button></p>
+  <p id="result">ここに合言葉が生成されます</p>
  <script src="./aikotobar.js"></script>
</body>
</html>
```
コードの説明をします。
- 何通りの合言葉が作れるかを示します。何通りかは`JavaScript`が計算します。
- 作成ボタンです。ボタンが押されたら～どうこうする、は`JavaScript`の仕事です。
- 合言葉が表示される場所です。

続いてはJavaScriptです。
`-`の赤色の部分は、消してください。

```diff_javascript:aikotobar.js
'use strict';

+const id = id => document.getElementById(id);

const arrayRandom = arr => arr[Math.floor(Math.random() * arr.length)];

const firstWords = ['夜の', ....];
const secondWords = ['最強の', ....];
const thirdWords = ['不死鳥', ....];

-console.log(arrayRandom(firstWords) + arrayRandom(secondWords) + arrayRandom(thirdWords));

+const kindsNumber = id('kinds');
+
+kindsNumber.innerText = firstWords.length * secondWords.length * thirdWords.length;
+
+const makeBtn = id('btn');
+
+const resutArea = id('result');
+
+makeBtn.onclick = () => {
+  resutArea.innerText = arrayRandom(firstWords) + arrayRandom(secondWords) + arrayRandom(thirdWords);
+}
```
コードの説明をします。
`index.html`の、`id`を設定しているタグを取得するには、
`document.getElementById(id名)`とするのですが、毎回これを打つのは大変なので、
一番上で`id`という短い名前で関数化しました。

`id`が`kinds`から取得した、`kindsNumber`は何通りかを表示する所です。
`kinds.innerText`で、何通りかを表示しています。

その後、作成ボタンと、合言葉表示欄を取得し、
`makeBtn.onclick = () => {}`とすることで、作成ボタンが押された時の処理を書くことができます。
前にコンソールに表示したものと同じものを、表示欄に、`innerText`で表示しています。

## 手順5:コピーボタンの機能

ボタンを押したら合言葉がコピーされます。
まずは`HTML`です。

```diff_html:index.html
....
<body>
  <h1>Aikotobar</h1>
  <p>合言葉を自動生成してくれるアプリです</p>
  <p>Aikotobarでは <sapn id="kinds"></sapn> 通りの合言葉を作成できます</p>
  <p><button id="btn">作成</button></p>
  <p id="result">ここに合言葉が生成されます</p>
+  <p><button id="copy">コピー</button></p>
  <script src="./aikotobar.js"></script>
</body>
</html>
```

次にJavaScriptです。

```diff_javascript:aikotobar.js
....
makeBtn.onclick = () => {
  resutArea.innerText = arrayRandom(firstWords) + arrayRandom(secondWords) + arrayRandom(thirdWords);
}

+function copy() {
+  navigator.clipboard.writeText(resutArea.innerText);
+}
+
+const copyBtn = id('copy');
+
+copyBtn.onclick = () => {
+  copy();
+  copyBtn.innerText = 'コピーしました！';
+  setTimeout(() => (copyBtn.innerText = 'コピー'), 1000);
+}
```
コードの説明をします。
`copy`という関数を実行すると、合言葉表示欄のテキストを取得し、コピーさせています。
「コピーする」というのは、パソコンにある **「クリップボード」にコピーしておく**ことなのです。
`Windows`の人は、`Windows`キー + `V`　で、クリップボードの副歴が見れます。
（文字列を切り取ってからうまく貼り付けられなっかたときなどに便利かも）

JavaScriptでクリップボードに文字列をコピーするには、
`navigator.clipboard.writeText(コピーしたい文字列)`とできます。

その後は、コピーボタンを取得し、押された時の挙動として、
1. クリップボードに書く
1. ボタンが「コピーしました！」になる
1. 1秒後に元に戻る

ようになっています。

## デザインの改善

`CSS`を編集しましょう。`style.css`を開きます。
このように編集します。
```css:style.css
body {
  text-align: center;
}

#btn {
  padding: 7px 18px;
  font-size: 25px;
  border-radius: 5px;
}

#result {
  padding: 25px;
  width: 60%;
  border: 2px solid #aaa;
  border-radius: 10px;
}

#result-div {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  flex-flow: column;
  justify-content: space-around;
  align-items: center;
}

#copy {
  padding: 7px 18px;
  font-size: 20px;
  border-radius: 5px;
}
```
また、`index.html`も少しだけ編集します。
```diff_html:index.html
<body>
  <h1>Aikotobar</h1>
  <p>合言葉を自動生成してくれるアプリです</p>
  <p>Aikotobarでは <sapn id="kinds"></sapn> 通りの合言葉を作成できます</p>
  <p><button id="btn">作成</button></p>
-  <p id="result">ここに合言葉が生成されます</p>
+  <div id="result-div">
+    <p id="result">ここに合言葉が生成されます</p>
+  </div>
  <p><button id="copy">コピー</button></p>
  <script src="./aikotobar.js"></script>
</body>
```
コードの説明をします。
`CSS`の一番上では、画面を中央寄せにしています。
その下では作成ボタンを装飾しています。
その下では最初の画像のような灰色の枠線を設定しています。
その下では合言葉表示欄を左右中央にしています。
このために、`index.html`を編集し、`div`タグで新たに囲ったのです。
最後のところはコピーボタンを装飾しています。

# 最終的な完成コード

<details><summary>index.html</summary>

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Aikotobar</title>
  <link rel="stylesheet" href="./style.css">
</head>
<body>
  <h1>Aikotobar</h1>
  <p>合言葉を自動生成してくれるアプリです</p>
  <p>Aikotobarでは <sapn id="kinds"></sapn> 通りの合言葉を作成できます</p>
  <p><button id="btn">作成</button></p>
  <div id="result-div">
    <p id="result">ここに合言葉が生成されます</p>
  </div>
  <p><button id="copy">コピー</button></p>
  <script src="./aikotobar.js"></script>
</body>
</html>
```

</details>

<details><summary>aikotobar.js</summary>

```javascript:aikotobar.js
'use strict';

const id = id => document.getElementById(id);

const arrayRandom = arr => arr[Math.floor(Math.random() * arr.length)];

const firstWords = ['夜の', 'ただただ', '終わりを告げる', '秋を彩る', '声が大きい', '先のとがった', '不老不死の', '黒き疾風の', 'こちらを見る', '大昔の', 'バズった', 'チリとなった', '空前絶後の', '難しく考えすぎる', 'なぜか', '持ち手のない', '悟りを開く', '暗闇に包まれた', '絶体絶命の', '嬉しそうな', '投げられた', 'ぶん投げられた', '最初で最後の', '最小の', '常識外れの', '世界に一つだけの', '奥が深い', '変に', '助けを求める', '虹色の'];
const secondWords = ['最強の', '惨めな', '考える', '始まりの', '最大の', '美しい', '白い', 'とても小さな', '灰色の', '剝がれた', '盗られた', '幼い', '悪賢い', 'ゴム製の', '最高な', '汚れた', '縮んだ', '曲がった', 'おかしい', '悟りを開く', '折れた', 'ヤバい', '勇者の', '巨大な', '挟まれた', '抜け出せない', '六千円する', '永遠の', '数学好きな', '百年後の', '薄い', '緑色の', '瑠璃色の', '謎の', 'うるさい', 'かわいそうな', '笑顔の', '怒った', '悲しみの', 'おもしろい'];
const thirdWords = ['不死鳥', '紅葉', '親友', 'ウグイス', '防寒着', '葉脈', '万年筆', '羊皮紙', '石ころ', '世界', 'ポスター', '財布', '幼稚園児', '大人', '木', 'クジャク', '退会ボタン', 'ピンポン玉', '宇宙', 'ロケット', '神', 'カッターナイフ', '映画', '米粒', '話', 'サル', 'ゾウ', 'レモン', 'ペット', '惑星', '定規', '英雄', '木箱', '鉄橋', '目覚まし時計', '学校', '病院', 'カレンダー', '鉛筆削り器', 'スプーン', 'ハンドル', 'ゴルフボール', '板', '浮き輪', 'ポット', '蛍光灯', '茶柱', '岩', '剣', '孫の手', '生卵', 'ぬいぐるみ', 'ギャグ', 'マウスポインタ', '椅子', 'カーテン', 'コンサート', 'アプリ', 'スマホ', '時計'];

const kindsNumber = id('kinds');

kindsNumber.innerText = firstWords.length * secondWords.length * thirdWords.length;

const makeBtn = id('btn');

const resutArea = id('result');

makeBtn.onclick = () => {
  resutArea.innerText = arrayRandom(firstWords) + arrayRandom(secondWords) + arrayRandom(thirdWords);
}

function copy() {
  navigator.clipboard.writeText(resutArea.innerText);
}

const copyBtn = id('copy');

copyBtn.onclick = () => {
  copy();
  copyBtn.innerText = 'コピーしました！';
  setTimeout(() => (copyBtn.innerText = 'コピー'), 1000);
}
```

</details>

<details><summary>style.css</summary>

```css:style.css
body {
  text-align: center;
}

#btn {
  padding: 7px 18px;
  font-size: 25px;
  border-radius: 5px;
}

#result {
  padding: 25px;
  width: 60%;
  border: 2px solid #aaa;
  border-radius: 10px;
}

#result-div {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  flex-flow: column;
  justify-content: space-around;
  align-items: center;
}

#copy {
  padding: 7px 18px;
  font-size: 20px;
  border-radius: 5px;
}
```

</details>

# 最後に

自分も初心者なので、最近注目されているように技術などにも、
これからはどんどん挑戦していきたいです。

ありがとうございました。