理系公務員のプログラミング日記

【ハンズオンJavaScript】最速でJavaScriptを扱えるようになる 2日目 クイズゲーム②

タグ:
JavaScript
クイズゲーム

ハンズオンJavaScriptを進めていく上での補助記事その2です。

  • やること:removeAttribute(),DRYの法則,const,function()
  • やらないこと:for,if,配列,Object,アロー関数 など

クイズゲームの作成 その2

おさらい

addEventListener(),getElementById() ,setAttribute() を使ってクイズゲームの最低限の機能を持たせた場合、 こんな感じになると思います。(cssはテキトー)

<!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>Document</title> <style> ul { list-style: none; margin-left: -20px; } li { width: 800px; height: 75px; margin-bottom: 10px; padding: 10px; font-size: 24px; border: 1px black solid; background-color: yellowgreen } .mondai { width: 800px; height: 200px; margin-left: 20px; padding: 10px; font-size: 24px; border: 1px black solid; background-color: orange; } .true { background-color: blue; color: white; } .false { background-color: red; color: white; } </style> </head> <body> <div class = "mondai"> <p>問題文</p> </div> <ul> <li id="A">A</li> <li id="B">B</li> <li id="C">C</li> <li id="D">D</li> </ul> </body> <script> document.getElementById("A").addEventListener("click", function () { this.setAttribute("class", "true"); this.textContent = "正解"; }) document.getElementById("B").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; }) document.getElementById("C").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; }) document.getElementById("D").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; }) </script> </html>

クイズ2日目start

複数選択すると下記のように全て色が変化します。

クイズ2日目start_1

removeAttributeでclass要素を削除する

同時に違う回答を選べるのはクイズとして良くないので、1度に選べる選択肢は1つにします。
そのために、「ある選択肢を選ぶと他の選択肢のclass属性と文字は元に戻る。」という仕様にしました。 removeAttribute("class") を使い、クリックした時にclass属性を削除するコードを追加します。

<script> document.getElementById("A").addEventListener("click", function () { this.setAttribute("class", "true"); this.textContent = "正解"; document.getElementById("B").removeAttribute("class"); document.getElementById("B").textContent = "B"; document.getElementById("C").removeAttribute("class"); document.getElementById("C").textContent = "C"; document.getElementById("D").removeAttribute("class"); document.getElementById("D").textContent = "D"; }) document.getElementById("B").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; document.getElementById("A").removeAttribute("class"); document.getElementById("A").textContent = "A"; document.getElementById("C").removeAttribute("class"); document.getElementById("C").textContent = "C"; document.getElementById("D").removeAttribute("class"); document.getElementById("D").textContent = "D"; }) document.getElementById("C").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; document.getElementById("A").removeAttribute("class"); document.getElementById("A").textContent = "A"; document.getElementById("B").removeAttribute("class"); document.getElementById("B").textContent = "B"; document.getElementById("D").removeAttribute("class"); document.getElementById("D").textContent = "D"; }) document.getElementById("D").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; document.getElementById("A").removeAttribute("class"); document.getElementById("A").textContent = "A"; document.getElementById("B").removeAttribute("class"); document.getElementById("B").textContent = "B"; document.getElementById("C").removeAttribute("class"); document.getElementById("C").textContent = "C"; }) </script>

クイズ2日目start_2

定数宣言のconstを使いをデータを一つにまとめる。 P32 2.3定数

上記のコードには同じキーワードがたくさん出てくるため、書くのは少し面倒でした。
ところで、プログラミングの世界にはDRY(Don't Repeat Yourself:繰り返しを避けろ)という原則があります。
これはAndy HuntとDave Thomaの著書「達人プログラマー」に出てくる有名な原則です。
(達人プログラマーは先日20周年記念版として第2版が出ました。オススメ。)
達人プログラマー ―熟達に向けたあなたの旅― 第2版

この原則に従い同じものは共通化していこうと思います。

まずは、JavaScriptで定数を宣言するキーワードであるconstを使います。 constを使い、何度も出てくるdocument.getElementById()を定数に代入します。

<script> const answerA = document.getElementById("A"); const answerB = document.getElementById("B"); const answerC = document.getElementById("C"); const answerD = document.getElementById("D"); document.getElementById("A").addEventListener("click", function () { this.setAttribute("class", "true"); this.textContent = "正解"; answerB.removeAttribute("class"); answerB.textContent = "B"; answerC.removeAttribute("class"); answerC.textContent = "C"; answerD.removeAttribute("class"); answerD.textContent = "D"; }) // 長いので以下略 </script>

これで少しスッキリしました。プログラミングにおいて読みやすいコードというものは正義です。
コードが短いことは多くの場合読みやすさに繋がります。
ですが、この処理の中には繰り返しがまだ存在しています。
この部分でほぼ同じ処理を3回繰り返しています。

answerB.removeAttribute("class"); answerB.textContent = "B"; answerC.removeAttribute("class"); answerC.textContent = "C"; answerD.removeAttribute("class"); answerD.textContent = "D";

関数を使い処理を一つにまとめる。 P110 3章 3.6 関数

同じ部分は関数を用いて一つにまとめることができます。
今回はfunctionキーワードによってremoveAnswer() という関数を宣言して、
「class属性を取り除く処理」と「テキストを初期状態(A ,B ,C ,D)に戻す処理」を関数の中にまとめました。

removeAnswer(answer)answer引数 と呼びます。 answerに"A"や"B"などを入れることで、関数内部のanswerを使用しているところに"A"や"B"が代入され実行されます。

<script> function removeAnswer(answer){ const answerElement = document.getElementById(answer); answerElement.removeAttribute("class"); answerElement.textContent = answer; } document.getElementById("A").addEventListener("click", function () { this.setAttribute("class", "true"); this.textContent = "正解"; removeAnswer("B"); removeAnswer("C"); removeAnswer("D"); }) document.getElementById("B").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; removeAnswer("A"); removeAnswer("C"); removeAnswer("D"); }) document.getElementById("C").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; removeAnswer("A"); removeAnswer("B"); removeAnswer("D"); }) document.getElementById("D").addEventListener("click", function () { this.setAttribute("class", "false"); this.textContent = "不正解"; removeAnswer("A"); removeAnswer("B"); removeAnswer("C"); }) </script>