Вот загадка:
Я пытаюсь создать игру для простого выбора пути, которая берет свое содержимое из локального JSON файла. При запуске он разбивает каждую сцену («Раздел» в файле JSON) на абзацы и добавляет первый абзац в DOM с прослушивателем событий, прикрепленным к окружающему div. Каждый раз, когда пользователь нажимает на «контейнер», из этого раздела добавляется еще один абзац, пока не отобразятся все абзацы.
После этого, если пользователь снова щелкает «контейнер», добавляются три варианта, каждый со своим собственным слушателем событий. При щелчке по одному из этих вариантов сцена (или «раздел») изменяется на выбранную. HTML «Контейнер» очищается, и процесс начинается снова, добавляя первый абзац новой сцены (раздела).
Проблема в том, что он отлично работает для первого раздела и вариантов, но после пользователь нажимает на выбор, он загружает два абзаца новой сцены, а не один. Он должен загрузить один абзац и ждать события нажатия, но на самом деле он загружает второй. Второй абзац загружается с помощью функции readyToUpdate, которая должна вызываться только прослушивателем событий (который не был запущен).
{
"Section_1": {
"Content": "Dark corner paragraph one<>Dark corner paragraph two<>Dark corner paragraph three",
"Choices": [
"Go to the garden<>24",
"Go to the terrace<>95",
"Go to the beach<>145"
]
},
"Section_24": {
"Content": "Garden paragraph one<>Garden paragraph two<>Garden paragraph three",
"Choices": [
"Go to the dark corner<>1",
"Go to the terrace<>95",
"Go to the beach<>145"
]
},
"Section_95": {
"Content": "Terrace paragraph one<>Terrace paragraph two<>Terrace paragraph three",
"Choices": [
"Go to the dark corner<>1",
"Go to the garden<>24",
"Go to the beach<>145"
]
},
"Section_145": {
"Content": "Beach paragraph one<>Beach paragraph two<>Beach paragraph three",
"Choices": [
"Go to the dark corner<>1",
"Go to the garden<>24",
"Go to the terrace<>95"
]
}
}
<div id="container"></div>
fetch("js/contentFile.json")
.then(response => response.json())
.then(json => initialSetup(json));
let narrativeText;
let gameData = {
section: "",
paraCount: 0,
choices: [],
choiceText: [],
choiceDest: [],
paragraphs: "",
paraSections: []
};
function updateParagraphs(){
console.log("Enter updateParagraphs");
let container = document.getElementById("container");
let node = document.createElement("p");
let textnode =
document.createTextNode(gameData.paraSections[gameData.paraCount]);
node.appendChild(textnode);
container.appendChild(node);
container.addEventListener('click', readyToUpdate, {once: true});
console.log(gameData.paraCount + " is less than " +
gameData.paraSections.length);
console.log("Exit updateParagraphs");
console.log(gameData);
}
function readyToUpdate(e) {
console.log("Enter readyToUpdate");
console.log(e);
gameData.paraCount ++;
let container = document.getElementById("container");
update();
console.log("Exit readyToUpdate");
console.log(gameData);
}
function choiceUpdater(e){
console.log("Enter choiceUpdater");
let choiceNumber = e.target.id.split("_")[1];
gameData.section = "Section_" + gameData.choiceDest[choiceNumber];
document.getElementById("container").innerHTML = "";
gameData.paraCount = 0;
update();
console.log("Exit choiceUpdater");
console.log(gameData);
}
function addChoices() {
console.log("Enter addChoices");
gameData.choices = narrativeText[gameData.section].Choices;
console.log(gameData.choices);
for (let i=0; i<gameData.choices.length; i++){
let choice = document.createElement("h4");
let choicesSplit = gameData.choices[i].split("<>");
gameData.choiceText[i] = choicesSplit[0];
gameData.choiceDest[i] = choicesSplit[1];
let choiceTextNode = document.createTextNode(gameData.choiceText[i]);
choice.appendChild(choiceTextNode);
choice.setAttribute("id", "choice_" + i);
choice.addEventListener("click", choiceUpdater, {once: true});
document.getElementById("container").appendChild(choice);
}
console.log("Exit addChoices");
console.log(gameData);
}
function update() {
console.log("Enter update");
gameData.paragraphs = narrativeText[gameData.section].Content;
gameData.paraSections = gameData.paragraphs.split("<>");
if (gameData.paraCount < gameData.paraSections.length) {
updateParagraphs();
}
else {
addChoices();
}
console.log("Exit update");
console.log(gameData);
}
function initialSetup(data) {
console.log("Enter initial setup")
narrativeText = data;
gameData.section = "Section_1";
gameData.paraCount = 0;
update();
console.log("Exit initial setup");
console.log(gameData);
};
Обновление: при изменении функции updateParagraphs как ниже, это работает. Но, глядя на производительность в Chrome разработчику, количество слушателей продолжает расти. Я использую Chrome 80, поэтому он должен удалить их, используя свойство Once, но у меня были те же начальные проблемы, даже когда я вручную удалял слушателей с помощью removeEventListener ().
function updateParagraphs(){
console.log("Enter updateParagraphs");
let container = document.getElementById("container");
let node1 = document.createElement("div");
node1.setAttribute("id", "innerContainer");
document.getElementById("container").appendChild(node1);
let innerContainer = document.getElementById("innerContainer");
let node = document.createElement("p");
let textnode =
document.createTextNode(gameData.paraSections[gameData.paraCount]);
node.appendChild(textnode);
innerContainer.appendChild(node);
innerContainer.addEventListener('click', readyToUpdate, {once: true});
}