Я делаю игру «Камень, ножницы, бумага» на серверной части Node.js с экспресс-сервером, клиентской частью frontend.js, файлами index.ejs и main.css. Сначала я хочу отобразить строковую строку результата вашего решения (выиграл, проиграл, то же самое — попробуйте еще раз).
Однако это не дает результата. Я попытался использовать console.info
, чтобы определить, передаются ли данные между маршрутами, что действительно происходит и буквально показывает, что данные находятся в шаблоне ejs, но они все равно не отображаются.
Я пытался использовать чат GPT, чтобы разобраться в этом, но безуспешно...
бэкэнд.js:
import express from "express";
import bodyParser from "body-parser";
import pg from "pg";
import ejs from "ejs";
import axios from "axios";
import { dirname } from "path";
import { fileURLToPath } from "url";
// import icons from "bootstrap-icons";
const __dirname = dirname(fileURLToPath(import.meta.url));
const app = express();
const port = 3000;
let gameResult = [];
app.set('view engine', 'ejs');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(express.static("public"));
app.get("/", (req, res) => {
const results = [...gameResult];
gameResult = [];
console.info("Result from session:", results);
res.render("index", {results});
});
app.post("/add", (req,res) => {
const {targetedId, dataIdList} = req.body;
let compSelector = dataIdList[Math.floor(Math.random() * dataIdList.length)];
console.info(`Chosen by client: ${targetedId}`);
console.info(`Chosen by computer: ${compSelector}`);
function determineResult(targetedId, compSelector) {
switch (targetedId) {
case "paper":
if (compSelector === "scissors") {
return "You lost";
} else if (compSelector === "rock") {
return "You won!";
} else {
return "The same, try again";
}
break;
case "scissors":
if (compSelector === "rock") {
return "You lost";
} else if (compSelector === "paper") {
return "You won!"
} else {
return "The same, try again";
}
break;
case "rock":
if (compSelector === "paper") {
return "You lost";
} else if (compSelector === "scissors") {
return "You won!"
} else {
return "The same, try again";
}
break;
default:
console.info("Error");
break;
}
}
try {
const result = determineResult(targetedId, compSelector);
console.info(result);
gameResult = [result];
res.redirect("/");
} catch (error) {
console.error("Error handling POST /add request:", error);
res.status(500).send("Internal Server Error");
}
});
app.listen(port, () => {
console.info(`Listening on port ${port}`);
});
интерфейс.js:
console.info("Frontend.js is loaded");
function myFrontFunction(event) {
const selectedImage = event.target;
const targetedId = selectedImage.getAttribute("data-id");
const images = document.querySelectorAll(".image");
const dataIdList = [];
images.forEach(dataId => {
dataIdList.push(dataId.getAttribute("data-id"));
});
console.info(`Data list: ${dataIdList}`);
// console.info(typeof(idData));
console.info(targetedId);
fetch("/add", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({targetedId, dataIdList}),
})
.then(response => {
if (response.ok) {
console.info("Data sent successfully");
response.text().then(text => console.info(text));
console.info("All images:", images);
images.forEach(image => {
if (image !== selectedImage){
console.info("Hiding image:", image);
image.classList.add('hidden'); // Use class to hide
}
});
} else {
console.error("Failed to send data to the server");
}
})
.catch(error => console.error("Error:", error));
}
индекс.ejs:
<%- include('partials/header.ejs') %>
<h1>The RSP App!</h1>
<h2>Choose Rock, Scissors or Paper:</h2>
<img class = "image" src = "/images/paper.png" alt = "A piece of paper" width = "400px" height = "400px" data-id = "paper" onclick = "myFrontFunction(event)">
<img class = "image" src = "/images/rock.png" alt = "A rock" width = "400px" height = "400px" data-id = "rock" onclick = "myFrontFunction(event)">
<img class = "image" src = "/images/scissors.png" alt = "Scissors" width = "400px" height = "400px" data-id = "scissors" onclick = "myFrontFunction(event)">
<div>
<% if (results.length > 0) { %>
<% results.forEach( result => { %>
<p> <%= result %></p>
<% }) %>
<% } %>
</div>
<script src = "/frontend.js"></script>
<%- include('partials/footer.ejs') %>
основной.css:
.hidden {
display: none;
}
Привет! Для меня это отображается, я не пробовал включать оператор <script src = "/frontend.js"></script>.
Из-за того, как вы настроили свой код, он не может отображать результаты. Давайте разберемся, что происходит:
/
и может выбрать одно из изображений.POST
на /add
на серверную часть с данными {targetedId: "scissors", dataIdList: ["paper", "rock", "scissors"]}
/add
выбирает случайный вариант, а затем проверяет результат.gameResults
теперь будет содержать результат и отвечать перенаправлением на /
. Обработчик маршрутизатора для этого маршрута затем примет и сбросит значение gameResults
, так что теперь gameResults
снова станет пустым массивом.response.text().then(text => console.info(text));
должна печатать HTML-разметку для всей страницы с отображаемыми результатами. Но поскольку со страницей, на которой находится пользователь, ничего не делается, ничего, кроме «скрытия» ненажатых изображений и консольного журнала разметки, не произойдет./
в обработчике /add
сбросило значение gameResults
на []
.Таким образом, по сути, вы в конечном итоге «игнорируете» результат, полученный с запросом на выборку, и в то же время отбрасываете значение на серверной стороне.
Итак, чтобы заставить ваш текущий код работать, вы можете отправить сам результат обратно в качестве ответа и добавить его на страницу в новом элементе, что-то вроде:
бэкэнд.js
try {
const result = determineResult(targetedId, compSelector);
res.send(result);
} catch (error) {
...
}
интерфейс.js
fetch(...)
.then(res => res.text())
.then(text => {
let p = document.createElement('p');
p.textContent = text;
document.querySelector('div').appendChild(p);
});
И есть много других способов сделать это, это зависит от того, как вы хотите это сделать. Если вы посмотрите на то, что @KooiInc ссылается в комментариях, вы увидите подход, который полностью работает на стороне клиента. Для новичка это может показаться немного пугающим, я рекомендую разделить строки несколькими символами новой строки, чтобы иметь лучший обзор и затем понять, что происходит.
Даже если вы хотите сделать это с помощью серверных вычислений и EJS, есть разные способы подойти к этому, но, как я уже сказал, в конечном итоге все сводится к тому, как вы хотите это сделать. Если вы хотите увидеть другой подход с бэкэндом+EJS, просто дайте мне знать :)
Действительно, почему это сложно? Это просто (довольно простая) игра