解決したいこと
Javascriptでまるばつゲームを作成中です。
コードは一通り記述したのですが、肝心の Javascriptが読み込めずゲームが作動しません。
現状は下の画像の通りです。
エラー文
Uncaught TypeError: Cannot read property 'addEventListener' of null at Object../app/javascript/app.js (app.js:95) at __webpack_require__ (bootstrap:19) at Object../app/javascript/packs/application.js (application.js:10) at __webpack_require__ (bootstrap:19) at bootstrap:83 at bootstrap:83 GET http://localhost:3000/app.js net::ERR_ABORTED 404 (Not Found) localhost/:71 GET http://localhost:3000/app.css net::ERR_ABORTED 404 (Not Found) localhost/:21 GET http://localhost:3000/app.js net::ERR_ABORTED 404 (Not Found) localhost/:71
app/assets/stylesheets/app.css
html { box-sizing: border-box; font-size: 16px; } *, *::before, *::after { box-sizing: border-box; } li { list-style: none; } body { margin: 0; line-height: normal; } h1 { margin: 20px 0; font-size: 2rem; font-weight: bold; } .wrapper { max-width: 1024px; margin: 0 auto; padding: 0 10px; text-align: center; } .game-container { padding: 60px 0; } .message-container { margin-bottom: 20px; font-size: 1.25rem; font-weight: bold; } .batsu { color: #00b0f0; } .maru { color: #ff0000; } .js-hidden { display: none; } .squares-container { margin: 0 auto; width: 202px; } .squares-box { width: 202px; height: 202px; display: flex; flex-wrap: wrap; border: solid 2px #333; } .square { position: relative; width: calc(198px / 3); height: calc(198px / 3); border: solid 2px #333; } .js-maru-checked::before { content: ''; width: 50px; height: 50px; border: solid 8px #ff0000; border-radius: 50%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); } .js-batsu-checked::before { content: ''; width: 50px; height: 8px; margin: auto; background-color: #00b0f0; border-radius: 4px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(45deg); } .js-batsu-checked::after { content: ''; width: 8px; height: 50px; margin: auto; background-color: #00b0f0; border-radius: 4px; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%) rotate(45deg); } .btn-container { padding-top: 40px; } .btn { display: inline-block; width: 150px; padding: 10px 20px; border-radius: 5px; cursor: pointer; } .btn-reset { color: #fff; background-color: #ffc000; font-weight: bold; } .btn-reset:hover { background-color: #ffd347; transition-duration: 0.4s; } /* JS連動 */ .js-unclickable { pointer-events: none; } .js-highLight { background-color: #fff2cc; }
app/views/layouts/index.html.erb
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8" /> <title>○×ゲーム</title> <link href="app.css" rel="stylesheet" /> </head> <body> <div class="wrapper"> <div class="game-container"> <div class="message-container"> <ul class="message-list"> <li id="maru-turn" class="js-hidden"> <span class="maru">○</span>の番 </li> <li id="batsu-turn"> <span class="batsu">×</span>の番 </li> <li id="maru-win" class="js-hidden"> <span class="maru">○</span>の勝ち! </li> <li id="batsu-win" class="js-hidden"> <span class="batsu">×</span>の勝ち! </li> <li id="draw" class="js-hidden"> 引き分け </li> </ul> </div> <div class="squares-container"> <div class="squares-box"> <!-- 1行め --> <div id="1-1" class="square"></div> <div id="1-2" class="square"></div> <div id="1-3" class="square"></div> <!-- 2行め --> <div id="2-1" class="square"></div> <div id="2-2" class="square"></div> <div id="2-3" class="square"></div> <!-- 3行め --> <div id="3-1" class="square"></div> <div id="3-2" class="square"></div> <div id="3-3" class="square"></div> </div> </div> <div class="btn-container"> <div class="js-hidden" id="reset-btn"> <span class="btn btn-reset">もう一回遊ぶ</span> </div> </div> </div> </div> <script src="app.js"></script> </body> </html>
app/javascript/app.js
let flag = false; let counter = 9; let winningLine = null; const squares = document.querySelectorAll('.square'); const squaresArray = [].slice.call(squares); // IE11対策 const messages = document.querySelectorAll('.message-list li'); const messagesArray = [].slice.call(messages); // IE11対策 const resetBtn = document.querySelector('#reset-btn'); // メッセージの切り替え関数 const setMessage = (id) => { messagesArray.forEach((message) => { if (message.id === id) { message.classList.remove('js-hidden'); } else { message.classList.add('js-hidden'); } }); } // 勝利判定のパターン関数 const filterById = (targetArray, idArray) => { return targetArray.filter((e) => { return (e.id === idArray[0] || e.id === idArray[1] || e.id === idArray[2]); }); } // 勝利判定パターン const line1 = filterById(squaresArray, ['1-1', '1-2', '1-3']); const line2 = filterById(squaresArray, ['2-1', '2-2', '2-3']); const line3 = filterById(squaresArray, ['3-1', '3-2', '3-3']); const line4 = filterById(squaresArray, ['1-1', '2-1', '3-1']); const line5 = filterById(squaresArray, ['1-2', '2-2', '3-2']); const line6 = filterById(squaresArray, ['1-3', '2-3', '3-3']); const line7 = filterById(squaresArray, ['1-1', '2-2', '3-3']); const line8 = filterById(squaresArray, ['1-3', '2-2', '3-1']); const lineArray = [line1, line2, line3, line4, line5, line6, line7, line8]; // 勝利判定関数 const isWinner = (symbol) => { // some: 1つでも条件を満たしていればTrueを返す const result = lineArray.some((line) => { // every: 全て条件を満たしていればTrueを返す const subResult = line.every((square) => { if (symbol === 'maru') { return square.classList.contains('js-maru-checked'); } else if (symbol === 'batsu') { return square.classList.contains('js-batsu-checked'); } }); if (subResult) { winningLine = line } return subResult; }); return result; } // ゲーム終了時の関数 const gameOver = () => { // 全てのマスをクリック不可にする squaresArray.forEach((square) => { square.classList.add('js-unclickable'); }); // 勝った時のマス目をハイライトする if (winningLine) { winningLine.forEach((square) => { square.classList.add('js-highLight'); }); } // リセットボタン表示 resetBtn.classList.remove('js-hidden'); } // ゲームの初期化の関数 const initGame = () => { flag = false; counter = 9; winningLine = null; squaresArray.forEach((square) => { square.classList.remove('js-maru-checked'); square.classList.remove('js-batsu-checked'); square.classList.remove('js-unclickable'); square.classList.remove('js-highLight'); }); setMessage('batsu-turn'); resetBtn.classList.add('js-hidden'); } resetBtn.addEventListener('click', function() { initGame(); }); // マスをクリックした時のイベント発火 squaresArray.forEach((square) => { square.addEventListener('click', () => { if (flag === true) { square.classList.add('js-maru-checked'); square.classList.add('js-unclickable'); if (isWinner('maru')) { setMessage('maru-win'); gameOver(); return; } setMessage('batsu-turn'); flag = false; } else { square.classList.add('js-batsu-checked'); square.classList.add('js-unclickable'); if (isWinner('batsu')) { setMessage('batsu-win'); gameOver(); return; } setMessage('maru-turn'); flag = true; } counter--; // 引き分け判定 if (counter === 0) { setMessage('draw'); gameOver(); } }); });
app/javascript/packs/application.js
// This file is automatically compiled by Webpack, along with any other files // present in this directory. You're encouraged to place your actual application logic in // a relevant structure within app/javascript and only use these pack files to reference // that code so it'll be compiled. require("@rails/ujs").start() // require("turbolinks").start() require("@rails/activestorage").start() require("channels") require("../app") // Uncomment to copy all static images under ../images to the output folder and reference // them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>) // or the `imagePath` JavaScript helper below. // // const images = require.context('../images', true) // const imagePath = (name) => images(name, true)
自分で試したこと
『Rails6でJavaScriptを使う方法』や、『JavaScript 読み込めない』等、検索してその記事通り記述を編集しても
解決にはいたりませんでした。
未熟者で手詰まりなので教えていただけると助かります。
回答1件
あなたの回答
tips
プレビュー