JavaScriptでクイズアプリを作る

HTML + CSS + JavaScript を使ってクイズアプリを作りました。問題数は少ないですが、遊んでみてください！

![スクリーンショット 2021-06-23 1.30.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1016415/b4b6d180-2d98-6d25-2520-5a92bca4d27d.png)

URL
https://cordelia-sixth.github.io/quiz_app_js/

ソースコード
https://github.com/cordelia-sixth/quiz_app_js

### ディレクトリ構成

```
app
 ├── index.html
 ├── script.js
 ├── style.css
 └── quiz_data_jp.js
```

<br>

```html:index.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
  <script type="module" src="script.js" defer></script>
</head>
<body>
  <div id="quiz-container">
    <div id="quiz-header">
      <h2 id="question">Question text</h2>
      
      <form id="quiz-form" name="quizForm">
        <ul>
          <li>
            <input type="radio" id="a" name="answer" value="a" />
            <label id="a-text" for="a">Question</label>
          </li>
          <li>
            <input type="radio" id="b" name="answer" value="b" />
            <label id="b-text"  for="b">Question</label>
          </li>
          <li>
            <input type="radio" id="c" name="answer" value="c" />
            <label id="c-text"  for="c">Question</label>
          </li>
          <li>
            <input type="radio" id="d" name="answer" value="d" />
            <label id="d-text"  for="d">Question</label>
          </li>
        </ul>  
      </form>
    </div>
    
    <button id="submit">回答する</button>

    <!-- 結果表示用の要素 -->
    <div id="results-container">
      <div id="results-header">
        <h2 id="results"></h2>
        <button id="next-quiz">次の問題へ</button>
      </div>
    </div>
  </div>
</body>
</html>
```

これはクイズに答えた結果を表示する要素です。初めはCSSで表示しないようにしてあります。

```html
<!-- 結果表示用の要素 -->
<div id="results-container">
  <div id="results-header">
    <h2 id="results"></h2>
    <button id="next-quiz">次の問題へ</button>
  </div>
</div>
```

<br>


```javascript:script.js
// クイズデータを読み込む
import { quizDataJp } from './quiz_data_jp.js';

// 問題文
const questionElm = document.getElementById('question');

// 選択肢
const a_text = document.getElementById('a-text');
const b_text = document.getElementById('b-text');
const c_text = document.getElementById('c-text');
const d_text = document.getElementById('d-text');

// 回答送信ボタン
const submitBtn = document.getElementById('submit');

// 現在の問題
let currentQuiz = 0;

// 現在のスコア
let score = 0;

// 次の問題へ進むボタン
const nextQuizBtn = document.getElementById('next-quiz');

// 結果表示用の要素
const quizHeaderElm = document.getElementById('quiz-header');
const resultsConElm = document.getElementById('results-container');
const resultsElm = document.getElementById('results');

loadQuiz();

// 問題を読み込む
function loadQuiz() {
  // 問題を取得
  const currentQuizData = quizDataJp[currentQuiz];

  // 質問文を表示
  questionElm.innerText = currentQuizData.question;

  // 選択肢を表示
  a_text.innerText = currentQuizData.a;
  b_text.innerText = currentQuizData.b;
  c_text.innerText = currentQuizData.c;
  d_text.innerText = currentQuizData.d;
}

// 回答を取得
function getAnswered() {

  // 選択したラジオボタンのvalueを返す
  return document.quizForm.answer.value;
}

// 結果表示
function showResults(results) {
  quizHeaderElm.style.display = 'none';
  submitBtn.style.display = 'none';
  resultsConElm.style.display = 'block';
  resultsElm.innerText = results;
}

// 次の問題を表示
function showQuiz() {
  quizHeaderElm.style.display = 'block';
  submitBtn.style.display = 'block';
  resultsConElm.style.display = 'none';
}

// 採点
function checkScore() {
  if (score == quizDataJp.length) {
    return '全問正解！おめでとう！';
  } else {
    return '曲を聞いてもう一回挑戦しよう！';
  }
}

submitBtn.addEventListener('click', event => {
  event.preventDefault();

  // 回答を取得
  const answer = getAnswered();

  // 回答している
  if(answer) {

    // 正誤判定
    if (answer === quizDataJp[currentQuiz].correct) {
      showResults('正解！');
      score++;
    } else {
      showResults('残念...');
    }

    // ラジオボタンの選択を解除する
    document.getElementById(answer).checked = false;
  }
});

nextQuizBtn.addEventListener('click', event => {
  event.preventDefault();

  // 次の問題へ進む
  currentQuiz++;

  // まだ問題が残っている
  if (currentQuiz < quizDataJp.length) {
    // 次の問題を読み込む
    loadQuiz();

    // 問題を表示する
    showQuiz();

  // 全ての問題に回答した
  } else {
    alert(checkScore());
    window.location.reload();
  }
});
```

##### 処理の流れ

1. 問題を表示する `loadQuiz()`
1. 答えを選択して回答するボタンをクリック `submitBtn.addEventListener()`
1. 回答を取得する `getAnswered()`
1. 正誤判定をして結果を表示する `showResults()`
1. 次の問題へ進むボタンを押す `nextQuizBtn.addEventListener()`
1. 問題が残っていればそれを読み込み、表示する `loadQuiz()` `showQuiz()`
1. すべての問題に回答していれば結果を判定して表示する `alert(checkScore())`
1. 最初の問題に戻る `window.location.reload()`

<br>

```css:style.css
@import url('https://fonts.googleapis.com/css2?family=Source+Sans+Pro&display=swap');

* {
  box-sizing: border-box;
}

body {
  background-color: #b8c6db;
  background-image: linear-gradient(315deg, #b8c6db 0%, #f5f7fa 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Source Sans Pro', sans-serif;
  margin: 0;
  min-height: 100vh;
}

#quiz-container {
  background-color: white;
  border-radius: 10px;
  box-shadow: 0 0 10px 2px rgba(100, 100, 100, 0.1);
  overflow: hidden;
  width: 600px;
  max-width: 100%;
  display: unset;
}

#quiz-header {
  padding: 4rem;
}

h2 {
  margin: 0;
}

ul {
  list-style-type: none;
  padding: 0;
}

ul li {
  font-size: 1.2rem;
  margin: 1rem 0;
}

ul li input {
  cursor: pointer;
}

ul li label {
  cursor: pointer;
}

button {
  background-color: #304dec;
  border: none;
  color: white;
  cursor: pointer;
  display: block;
  font-family: inherit;
  font-size: 1.1rem;
  width: 100%;
  padding: 1.3rem;
}

button:hover {
  background-color: #233bc4;
}

#results-container {
  display: none;
  align-items: center;
}

#results-header {
  text-align: center;
  justify-content: center;
}

#results {
  padding: 2rem 0;
}
```

<br>

## 今回の学び
クイズデータの表現方法と、その呼び出し方に触れることができたのが1番の学びでした。配列とオブジェクトを組み合わせるのは楽しかったです。データ構造に関してもっと勉強したくなりました！

## 今後の課題
課題は処理の切り出し方だと思いました。開発を進めていくにつれ、必要な処理が増えていきますがそれをどう分割すればいいのかまだわかっていません。油断していると1つの処理の中にすべて書いてしまいそうになります。

それと変数や関数などの名前が分かりにくいですね。もっと他の方のコードや書籍を読んで勉強します！

<br>

読んでいただきありがとうございました！フィードバックしていただけたらとても嬉しいです！

## 参考

https://www.youtube.com/watch?v=dtKciwk_si4&t=1873s

## My Link
Github
https://github.com/cordelia-sixth

Products
https://raindrop.io/cordelia/my-products-18715918

Qiita
https://qiita.com/cordelia

Twitter
https://twitter.com/cordelia_sixth