クイズアプリを作ってフロントエンドの基礎を学ぶ　第１回(全２回)

## JavaScriptクイズアプリ
このアプリの作成には、HTML、CSS、Java Scriptの基本とイベントの使⽤、DOM(Document Object Mode:ブラウザーが読み込んだwebページのこと)の操作、の技術を使⽤します。
課題や追加機能は**自分で調べて**完成させてみましょう。

#### 完成イメージ
![image (6).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499102/8017f54b-d9c8-d3ec-5e27-0a7538429554.png)
![image (4).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1499102/e796fbfe-7d3c-920b-7371-8d9319b5387c.png)


## 1. プロジェクトのフォルダ、ファイル
アプリのフォルダ構成は以下の通りです。⼀般的にフォルダ直下にindex.htmlがあり、JavaScriptとCSSのファイルは分けて管理します。

・Visual Studio Codeで新規フォルダを作成(quiz-app-⽒名)、フォルダ内でindex.htmlファイルとcssとjsのフォルダをさらに作成
・cssフォルダ内でstyle.css、jsフォルダ内でapp.jsとdata.jsを新規で作成

```
┬quiz-app-⽒名
│└index.html
├css
│└style.css
└js
 ├app.js
 └data.js
```

※最初のHTMLファイルをファイル名index.htmlで保存するのは⼀般的です。
※だいたいのWebサーバーでは、index.htmlというファイルをディレクトリでチェックします。 ⾒つかった場合、サーバーはそのファイルを返します。

##2. HTML
クイズアプリは１ページ(index.html)で構成されています。
HTML構造は以下をご覧ください。
・ページがHTML5という意味のタグ ```<!DOCTYPE html>```
・ページの⾔語を設定します。 ```<html lang="ja">```
・headタグ内で、ページに関する様々な情報を設定

```html
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <title>Quiz App</title>
    <meta name="description" content="">
    <meta name="viewport" content="width=device-width">
    <link rel="stylesheet" href="css/style.css">
</head>
```
・bodyタグ内で、ブラウザーで画⾯に表⽰するものの初期データを設定

```html
<body>
    <div class="wrapper">
        <h1>クイズアプリ</h1>
        <p id="time">スタート！</p>
        <div id="mainContent">
            <h3 id="question"></h3>
            <div id="choices"></div>
            <p><button id="submit"></button></p>    
        </div>
    </div>
</body>
```

・scriptタグでは、指定されたパスのJavaScriptが実⾏
※HTMLは上から読まれます。app.js内でdata.jsのデータを使いたいので、先にdata.jsを設定します。

```html
<script src="js/data.js"></script>
<script src="js/app.js"></script>
```

・最後は```<html lang="ja">``` の終了タグ
```</html>```

##3. CSS
CSSは下記4つの要素を含むように作成してください。

・クイズアプリは画⾯中央にくる
・確定ボタンとラジオボタンの元々のスタイルを変える
・ボタンをマウスオーバーした時に⾊が変わる
・画⾯のバックグラウンド⾊とテキストの⾊を変える
　※フォントサイズ、⾊などを⾃由に調整して下さい

例として、以下を参照してください。

```css
body {
  margin: 0;
  padding: 0;
  overflow: auto;
  font-size: 1.5em;
  background-color: #313131;
  color: #f7f7f7;
}

.wrapper {
  width: 400px;
  margin: 0 auto;
}

#submit {
  background-color: #ededed;
  border-radius: 6px;
  border: 1px solid #615961;
  display: inline-block;
  cursor: pointer;
  color: #777777;
  font-family: Arial;
  font-size: 18px;
  font-weight: bold;
  padding: 10px 41px;text-decoration: none;
  text-shadow: 0px 1px 0px #ffffff;
}

#submit:hover {
  background-color: #dfdfdf;
}

#submit:active {
  position: relative;
  top: 1px;
}
```

##4. クイズアプリで使う質問と答えのデータ
data.jsファイルにはデータのみを保存します。

・quizDataの配列を作成
　```var quizData = []```

・配列内で各質問のオブジェクトを作成
　```var quizData = [{},{},{},{}];```

・オブジェクト内で、3個のプロパティを⽤意してください
　質問："question"（⽂字列）
　選択肢："choices"（4つ⽂字列の配列）
　正解："correct"（⽂字列） 

・3個のプロパティの値は、質問や選択肢を⾃由に考えて追加してください

```js
"question": "5+5",
"choices": ["10", "55", "5", "0"],
"correct": "10"
```

※複数の質問のオブジェクトを作ってください。（3個以上）

##5. HTMLの要素の⽤意
ここからの処理はapp.jsに書きます。
※index.htmlを⾒ると、 ```<script src="js/app.js"></script>``` が⼀番下にあるので、順番的に⼀番最後に読まれます。
JavaScriptを使⽤してHTMLを変更するには、HTMLタグを取得してオブジェクトに格納する必要があります。
取得するには、タグのIDまたはCLASS名などを使います。
```<p id="time">スタート！</p>``` の場合は、 ```document.getElementById('time')``` で取得できます。

詳しくは以下の資料を確認してください。
https://developer.mozilla.org/ja/docs/Web/API/Document/getElementById

app.jsで次のようにオブジェクトを作って、各要素にアクセスするようにしてください

```js
var content
var question
var choice
var submit
```

##6. 初期値を設定
初期状態の変数、フラグ、タイマーの設定などを準備します。

```javascript
var turn // 順番のインデックス、0に設定してください
var score // 正解の答えを数える変数、初期としては0に設定してください
var askingQuestion // フラグです。trueは答えを確認する。falseは次の答えを⽤意するもしくは結果をだす。初期としてはどれを設定するか考えて、両⽅を試してください。
var setTimer // 残り時間（秒数）を設定してください
```
上記の変数はソース内でどこでも使えます。

##7. タイマーの処理
次はタイマーのファンクションを作成します。
```<p id="time">スタート！</p>``` に残り時間を計算して表⽰させます。
初期値のsetTimerには何秒かタイムリミットが設定されています。

setIntervalはwindowオブジェクトのメソッドです。使い⽅としては、メソッド内のファンクションが⾃動的に指定された時間ごとに何回も⾛ります。
このようなメソッドで使⽤するときの秒数は 1秒=1000ミリ秒 です。
```setInterval(function(){ここの処理が⾛る}, 指定時間（ミリ秒）);```
```clearInterval(この中にsetIntervalの処理を⼊れる)``` を使うと処理が⽌まります。

```js
document.getElementById('time').innerHTML="残り: " + setTimer + "秒"; //初期秒数を表示させる
var timer = setInterval(function(){ //１秒ごとに処理
  setTimer--; // ⼀個を減らす
  document.getElementById('time').innerHTML="残り: " + setTimer + "秒"; //HTMLにタイマーを表⽰
  if (setTimer === 0){
    // ここでsetIntervalの処理を⽌めるようにしてください(windowオブジェクトのメソッド)
    // HTML要素timeに終了と表⽰してください
    // アラートのメソッドを使って時間切れなどのメッセージを表⽰させてください
    alert("タイムアップ！");
    // showResultsのファンクションを呼び出して、結果の画⾯を表⽰させてください
   }
 }, 1000); // 1000ミリ秒にすることで1秒ずつカウントできる
```

##8. 質問を作成する関数
質問を作成するためのファンクションです。
・turnは初期状態で0なので、0からスタート（このファンクションが⾛ったら、別のところでturnは+1追加されます）
・quizData（別JSのデータ）の配列からインデックス0のオブジェクトをchoicesに格納
・各質問のためラジオボタンをループで作成
・HTMLに作った質問とラジオボタンを表⽰turnが0のままだったら、確定ボタン名をSubmitにする（１回⽬だけ⾏う、２回め以降は別の場所でボタン名が変わる）

```js
function createQst() {
  var choices = quizData[turn].choices; // 今の順番の質問の配列を作る
  var choicesHtml = ""; // ここに格HTMLのラジをボタンを⼊れる

  // クイズ選択のラジオボタンを作る
  for (var i = 0; i < choices.length; i++) { // 格配列の値に対して、HTMLのラジオボタンを
  作る。インデックスに対した値を⼊れる。
    choicesHtml += "<input type='radio' name='quiz" + turn + "' id='choice" + (i + 1) + "' value='" + choices[i] + "'>" + " <label for='choice" + (i + 1) + "'>" + choices[i] + "</label><br>";
  }

  // HTMLに質問を⼊れる
  question.textContent = "No." + (turn + 1) + " " + quizData[turn].question;

  // 上で作ったラジオボタンをHTMLに⼊れる
  choice.innerHTML = choicesHtml;

  // ⼀番⽬の質問のボタン名を作る
  if (turn === 0) {
    submit.textContent = "Submit";
  }
}
```

##9. 確定ボタンの処理
確定ボタンを押すときに実⾏されるファンクションです。

・askingQuestionのフラグはtrueの場合は、結果を表⽰される処理が⾛る
・ボタン名をNextに変更、askingQuestionをfalseに戻す（次回実⾏の時、次の質問が表⽰されるため）
・各ラジオボタンを取得して、チェックされた項⽬とデータ内のcorrectは⼀致しているかどうか確認する
・結果に応じてHTMLの作成と表⽰
・askingQuestionのフラグはfalseの場合は、結果を表⽰される処理が⾛る
・ボタン名をSubmitに変更、askingQuestionをtrueに戻す（次回実⾏のため）
・データの最後の質問まで⾏ったかどうか、quizData.lengthをチェックする
・最後じゃない場合は、turnに+1を追加
・最後の場合は、タイマーをクリアして、結果の画⾯を表⽰するファンクションを呼び出す

```js
function checking() {
// クイズに答えるか、次の質問に進むかを確認する
if (askingQuestion) {
  submit.textContent = "Next"; // nextボタンに変える
  askingQuestion = false; // またsubmitを押したら、次の質問に移動する為、フラグをfalseに変える

  var selectedAnsw; // 押したラジオボタンを習得する
  var correctIndex; // 正解の値のインデックスを習得
  var radios = document.getElementsByName("quiz" + turn); // 上で作った今の順番のラジオボタンを習得

  for (var i = 0; i < radios.length; i++) { // 習得した全ラジオボタンをチェックする
    if (radios[i].checked) {
      selectedAnsw = radios[i].value; // 押されたボタンの答えを習得
    }

    if (radios[i].value == quizData[turn].correct) {
      correctIndex = i; // 正解の答えのインデックスを習得
    }
  }

  var labelStyle = document.getElementsByTagName("label")[correctIndex].style;
// 正解のインデックスに紐づく答えのhtmlのスタイルを作る
  labelStyle.fontWeight = "bold";
  if (selectedAnsw == quizData[turn].correct) { // 選択した答えと正解の答えを⽐較
    // 正解と⼀致した時、スコアを追記、⾊を緑に。⼀致しない場合、⾚にする。
    score++;
    labelStyle.color = "green";
  } else {
    labelStyle.color = "red";
  }

 } else { //次の質問を⽤意する
  askingQuestion = true; // フラグをリセットする
  submit.textContent = "Submit"; // ボタン名submitに戻す
  if (turn < quizData.length - 1) { // クイズの格データのインデックス数に対する順番を設定
    turn++; //次の順番をセット
    createQst(); // 次の質問を作成する処理を⾛らせる
  } else { // 最後の順番になったら、タイマーをクリア、結果を表⽰する
    clearInterval(timer);
    showResults();
  }
 }
}
```

##10. 結果の出⼒処理
quizDataの全部の質問が終わったら、もしくはタイマーの時間が過ぎたら結果の画⾯をこのファンクションで作成します。
・checking()の中で、正解の場合、scoreに追加された合計をここでHTMLごと作って表⽰します
・scoreは0の場合、全問不正解を表⽰します

```js
function showResults() {
  if (score != 0) { // スコアーが０以降だったら、以下のHTMLを表⽰
    content.innerHTML = "<h2>お疲れ様でした！</h2>" + 
    "<h2>以下結果になります、</h2>" +
    "<h2>" + quizData.length + "問中、"+ score + "問正解、" +
    Math.round(score / quizData.length * 100) + "%<h2>";
  }
  else { // スコアーが０だったら、全問不正解を表⽰する。
    content.innerHTML = "<h2>お疲れ様でした！</h2>" +
    "<h2>以下結果になります、</h2>" +
    "<h2 style='color:red'>全問不正解！<h2>";
  }
}
```

##11. イベントの設置
ここまで作ったソースは実⾏しても何も動かないですね。
なぜならば、最初に作った変数は実⾏されますが、ブラウザーのメモリーに保存されたまま画⾯に表⽰されません。
同じく、各ファンクションがメモリーに保存されたまま、呼び出されるまで実⾏されません。

・最初に実⾏させたいファンクションはcreateQstです。
JavaScriptでは全ページがロード終わったら、⾃動的に⾛る"load"イベントがあります。
`window.addEventListener("load", event);`
loadの2個⽬の引数は、イベントの処理です。

`window.addEventListener("load", createQst, false);`

・ソースの⼀番上に作った確定ボタンのオブジェクト `var submit =
document.getElementById("sub");` にクリックイベントを付けます。
そうすると、ボタンを押した際に、checking()の中の処理が実⾏されます。
`submit.addEventListener("click", checking, false);`

**クイズアプリの作成は終了です。次は下記リンクからクイズアプリをjQueryに書き換えて課題を完成させてみよう！**

[・クイズアプリを作ってjQueryの基礎を学ぶ　第２回(全２回)](https://qiita.com/hamaguri/items/36d7c3b39850b2c961f6)

https://qiita.com/hamaguri/items/36d7c3b39850b2c961f6

###課題
* 結果の画⾯でやり直しのボタンを追加
* 答え終わった時にタイマーを⽌める
* 問題をランダムに出す