簡単なHTML+JS+CSSでも、クイズゲームは作れる!でも100行くらいになったらCSS/JSは別ファイルにすべきだな…。
タイピングは英単語を登録するだけでいいけど、クイズは問題を用意するのが面倒だな。
ブラウザだけで実行できるので、ローカルのデスクトップでも動作する。
動作デモ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>クイズのWebアプリ</title> <style> /* Window全体の設定 */ body{ background: #efdec1; font-size: 14px; font-family: Verdana, sans-serif; } /* メイン部分の設定 */ .container{ width: 400px; /* 横幅は狭め */ margin: 8px auto; /* 上下8pxで、中央揃い */ background: #fff; /* 背景色は白 */ border-radius: 4px; /* 四隅は丸め */ padding: 16px; /* 内側の余白は多め */ } /* 問題文 */ #question{ margin-bottom: 16px; /* 下にぴったりくっつかないようにする */ font-weight: bold; /* 太字にして強調 */ } /* 選択肢の枠の部分 */ #choices{ list-style: none; /* 先頭の・を消す */ padding: 0; /* 内側の余白は無しにして、ぴったり感をだす */ margin-bottom: 16px; /* 下のボタンとの間を、少しあける。 */ } /* 実際の選択肢の枠の部分 */ #choices > li { border: 1px solid #ccc; /* 灰色の枠線 */ border-radius: 4px; /* 四隅は丸め */ padding: 10px; /* 内側の余白は多め */ margin-bottom: 10px; /* 次の選択肢との余白 */ cursor: pointer; /* マウスが人差し指になる */ } /* マウスを乗せると色が変わる */ #choices > li:hover { background: #f8f8f8; } /* 正解の選択肢の場合 */ #choices > li.correct { background: #d4edda; border-color: #c3e6cb; color: #155724; font-weight: bold; } /* 選択肢の後ろに擬似クラスを使って、文字列を追加する */ #choices > li.correct::after { content: ' ← 正解!'; } /* 間違いの選択肢の場合 */ #choices > li.wrong { background: #f8d8da; border-color: #f5c6cb; color: #721c24; font-weight: bold; } /* 選択肢の後ろに擬似クラスを使って、文字列を追加する */ #choices > li.wrong::after { content: ' ← 間違い!'; } /* 次の問題へボタン(結果発表ボタン) */ #btn, #result > a { background: #3498db; padding: 8px; border-radius: 4px; cursor: pointer; text-align: center; /* ボタンなので、文字は中央揃い */ color: #fff; box-shadow: 0 4px 0 #2880b9; /* x方向の影, y方向の影, ぼかし度合い, 色 */ } /* ボタンが押せない状態 */ #btn.disabled{ background: #ccc; box-shadow: 0 4px 0 #bbb; opacity: 0.7; } /* 結果発表(普段は隠しておく) */ #result { position: absolute; /* 普段は画面の上(外側)に隠しておく(y軸の-500) */ width: 300px; background: #fff; padding: 30px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); top: 50px; /* windowsの上から50px */ left: 0; right: 0; margin: 0 auto; /* 中央揃い */ text-align: center; /* 文字も中央揃い */ border-radius: 4px; /* 角丸 */ transition: 0.4s /* 画面外の上から、0.4秒かけて中央に表示される */ } /* 非表示の時の場所 */ #result.hidden{ /* 普段は画面の上(外側)に隠しておく(y軸の-500) */ transform: translateY(-500px); } /* 結果の文字列 */ #result > p{ font-size: 24px; } /* 自分自身のリンクで初期化(最初からクイズをやる) */ #result > a{ display: block; /* ブロック要素にすると親要素の幅になる */ text-decoration: none; /* リンクの下線を消す */ } </style> </head> <body> <main> <section class="container"> <p id="question"></p> <ul id="choices"></ul> <div id="btn" class="disabled">次の問題へ</div> <section id="result" class="hidden"> <p id="scoreLabel"></p> <a href="">再挑戦?</a> </section> </section> </main> </body> <script> 'use strict'; { // クイズの問題文の表示領域 const question = document.getElementById('question'); // クイズの問題文の選択肢を表示する領域 const choices = document.getElementById('choices'); // 次の問題へボタン const btn = document.getElementById('btn'); // 回答結果を表示する領域(普段は画面外に隠してある) const result = document.getElementById('result'); // 文字列部分 const scoreLabel = document.getElementById('scoreLabel'); // 最初の選択肢が正解 const quizSet = shuffle([ {q: '世界一面積の大きい国は?', c:['ロシア','カナダ','アメリカ', '中国']}, {q: '一番人口の少ない都道府県は島根県である。○か×か?', c:['×','○']}, {q: '東京スカイツリーの高さは何mでしょうか?', c:['634メートル','563メートル','788メートル']}, {q: '「原作の漫画が一番売れた」作品は?', c:['ドラゴンボールZ','スラムダンク','ドラえもん', '名探偵コナン']}, {q: '「雇用・利子および貨幣の一般理論」を書いた人物は誰か?', c:['ケインズ','ゲーテ','カント', 'マルクス', 'ケンケン']} ]); let currentNum = 0; //何問目か? let isAnswered; // 回答中か? let score = 0; // 正解数 // 選択肢の順番をシャッフル function shuffle(arr){ // シャッフル・アルゴリズムFisher–Yates(フィッシャー・イェーツ) for(let i= arr.length-1; i>0; i--){ const j = Math.floor(Math.random() * (i+1)); [arr[j], arr[i]] = [arr[i], arr[j]]; // 分割代入で入れ替える } return arr; } // 正解かどうかの判定 function checkAnswer(li){ //回答中以外に選択肢を押されても無視 if(isAnswered){ return; } isAnswered = true; // 最初の選択肢だったら正解 if(li.textContent === quizSet[currentNum].c[0]){ li.classList.add('correct'); score++; }else{ li.classList.add('wrong'); } // 次の問題へボタンを押せるようにする btn.classList.remove('disabled'); } // 問題を出す function setQuiz(){ isAnswered = false; // 未回答で初期化 // 問題文を表示 question.textContent = quizSet[currentNum].q; // 前の問題文をクリア while(choices.firstChild){ choices.removeChild(choices.firstChild); } // 選択肢を表示。 // そのままshuffle関数に配列を引数で渡すと参照渡しになってしまうので、スプレット演算子(...)で展開してコピーを渡す const shuffledChoices = shuffle([...quizSet[currentNum].c]); // 選択肢の数だけ繰り返す shuffledChoices.forEach(choice =>{ // 選択肢の要素を生成して、選択肢の文字列を乗せる const li = document.createElement('li'); li.textContent = choice; // 選択肢をクリックされたら正誤判定 li.addEventListener('click', ()=>{ checkAnswer(li); }); // 親要素に追加 choices.appendChild(li); }); // 全問回答したら、次の問題へボタンではなく、成績を表示するボタンに変更する if(currentNum === quizSet.length-1 ){ btn.textContent = '成績を表示する'; } } // 関数以外の初めての処理。問題を出題する setQuiz(); // 次の問題ボタンを押された時の処理 btn.addEventListener('click', ()=>{ // 回答中は次の問題へ行けない if(btn.classList.contains('disabled')){ return; } btn.classList.add('disabled'); // 全問回答したら、成績を表示する if(currentNum === quizSet.length - 1){ scoreLabel.textContent = `正解率: ${score} / ${quizSet.length}`; // 隠しておいた結果を表示する result.classList.remove('hidden'); // まだ問題が残っていたら、次の問題を表示する }else{ currentNum++; setQuiz(); } }); } </script> </html> |