我最近遇到了一个问题,即我的脚本无法访问通过编辑同一脚本中的innerHTML 插入的元素。
所以,我的 HTML 有这个占位符代码:
<div class="stage_preset_selection_column">
<div class="stage_preset" id="stage_preset_1">
<!-- <div class="preset_number">Preset 1</div>
<div class="preset_title">title of the preset</div>
<div class="questions_stage stage_preset_information">
<div class="preset_text">questions per stage:</div>
<div class="preset_text_number">5</div>
</div>
<div class="number_stages stage_preset_information">
<div class="preset_text">number of stages:</div>
<div class="preset_text_number">13</div>
</div>
<div class="number_failure stage_preset_information">
<div class="preset_text">number of f for failure:</div>
<div class="preset_text_number">3</div>
</div>
<div class="last_edited">last edited: 30-06-2021 14:51</div>
<img src="../../assets/elements/cross.png" alt="remove preset" class="remove_preset">
<img src="../../assets/elements/cross_inverted.png" alt="remove preset" class="remove_preset_inverted"> -->
<!-- <div class="preset_number toggle_empty_preset">Preset 2</div>
<div class="empty_preset_title">Empty preset</div> -->
</div>
<div class="stage_preset" id="stage_preset_2"></div>
</div>
<div class="stage_preset_selection_column">
<div class="stage_preset" id="stage_preset_3"></div>
<div class="stage_preset" id="stage_preset_4"></div>
</div>
然后在启动时使用以下 JavaScript 代码进行编辑:
function updatePreset() {
fs.readFile(path.join(__dirname, '/stage_presets.json'), 'utf8', (err, data) => {
if(err) {
console.log(`Error reading file from disk: ${err}`);
} else {
const stage_presets = JSON.parse(data);
Object.values(stage_presets).forEach(preset => {
let htmlPresetElement = document.getElementById(`stage_preset_${preset.stage_preset_number}`)
if(preset.is_empty) {
htmlPresetElement.innerHTML = `<div class="preset_number toggle_empty_preset">Preset ${preset.stage_preset_number}</div>
<div class="empty_preset_title">Empty preset</div>`
} else {
htmlPresetElement.innerHTML = `<div class="preset_number">Preset ${preset.stage_preset_number}</div>
<div class="preset_title">${preset.preset_title}</div>
<div class="questions_stage stage_preset_information">
<div class="preset_text">questions per stage:</div>
<div class="preset_text_number">${preset.questions_per_stage}</div>
</div>
<div class="number_stages stage_preset_information">
<div class="preset_text">number of stages:</div>
<div class="preset_text_number">${Object.keys(preset.stages).length}</div>
</div>
<div class="number_failure stage_preset_information">
<div class="preset_text">number of f for failure:</div>
<div class="preset_text_number">${preset.f_for_failure}</div>
</div>
<div class="last_edited">last edited: ${preset.last_edited}</div>
<img src="../../assets/elements/cross.png" alt="remove preset" class="remove_preset">
<img src="../../assets/elements/cross_inverted.png" alt="remove preset" class="remove_preset_inverted" id="remove_preset_inverted_${preset.stage_preset_number}">`
}
});
}
});
}
所以现在我的问题是,由于某种原因,当我尝试为 id“remove_preset_inverted_[num]”的元素创建 EventListener 时,我收到此错误:
Uncaught TypeError: Cannot read property 'addEventListener' of null
所以我的问题是,为什么会发生这种情况以及如何解决它?到目前为止,我尝试过的每个解决方案都失败了。
谢谢
编辑:添加了可运行的代码片段 由于某种未知的原因,它在代码片段中起作用,但在我的代码中不起作用。这和我在插入元素的函数中使用 fs.readFile 有关系吗?
stage_presets = {
"stage_preset_1": {
"stage_preset_number": 1,
"preset_title": "Test Preset!",
"is_empty": false,
"questions_per_stage": 5,
"last_edited": "Sun, 04 Jul 2021 20:13:19 GMT",
"f_for_failure": 3,
"probability_easy": 60,
"probability_medium": 25,
"probability_hard": 15,
"stages": {
"grade_1": {
"title": "Grade 1",
"questions": {
"question_1": {
"question": "When mokey do funny, what happen?",
"answer": "everyone laughs :)",
"difficulty": "easy",
"subject": "science"
},
"question_2": {
"question": "What's 1+1?",
"answer": "idk",
"difficulty": "hard",
"subject": "maths"
}
}
},
"grade_2": {
"title": "Grade 2",
"questions": {
"question_1": {
"question": "What was the word 'crap' named after?",
"answer": "Thomas Crapper",
"difficulty": "easy",
"subject": "history"
},
"question_2": {
"question": "",
"answer": "",
"difficulty": "medium",
"subject": "chaos"
}
}
},
"grade_3": {
"title": "Grade 3",
"questions": {
"question_1": {
"question": "How does banana market fluctuation influence prices?",
"answer": "monkey regulation",
"difficulty": "easy",
"subject": "political_science"
},
"question_2": {
"question": "",
"answer": "",
"difficulty": "hard",
"subject": "litterature"
},
"question_3": {
"question": "rohulk?",
"answer": "this is gonna be messy",
"difficulty": "medium",
"subject": "osu"
}
}
},
"grade_4": {
"title": "Grade 4",
"questions": {
"question_1": {
"question": "",
"answer": "",
"difficulty": "hard",
"subject": "pe"
}
}
}
}
},
"stage_preset_2": {
"stage_preset_number": 2,
"preset_title": "New preset",
"is_empty": false,
"questions_per_stage": 5,
"last_edited": "Sun, 04 Jul 2021 18:49:54 GMT",
"f_for_failure": 3,
"probability_easy": 60,
"probability_medium": 25,
"probability_hard": 15,
"stages": {}
},
"stage_preset_3": {
"stage_preset_number": 3,
"preset_title": "New preset",
"is_empty": false,
"questions_per_stage": 5,
"last_edited": "Sun, 04 Jul 2021 18:49:52 GMT",
"f_for_failure": 3,
"probability_easy": 60,
"probability_medium": 25,
"probability_hard": 15,
"stages": {}
},
"stage_preset_4": {
"stage_preset_number": 4,
"preset_title": "New preset",
"is_empty": false,
"questions_per_stage": 5,
"last_edited": "Sun, 04 Jul 2021 19:02:58 GMT",
"f_for_failure": 3,
"probability_easy": 60,
"probability_medium": 25,
"probability_hard": 15,
"stages": {}
}
}
function updatePreset(stage_presets) {
Object.values(stage_presets).forEach(preset => {
let htmlPresetElement = document.getElementById(`stage_preset_${preset.stage_preset_number}`)
if(preset.is_empty) {
htmlPresetElement.innerHTML = `<div class="preset_number toggle_empty_preset">Preset ${preset.stage_preset_number}</div>
<div class="empty_preset_title">Empty preset</div>`
} else {
htmlPresetElement.innerHTML = `<div class="preset_number">Preset ${preset.stage_preset_number}</div>
<div class="preset_title">${preset.preset_title}</div>
<div class="questions_stage stage_preset_information">
<div class="preset_text">questions per stage:</div>
<div class="preset_text_number">${preset.questions_per_stage}</div>
</div>
<div class="number_stages stage_preset_information">
<div class="preset_text">number of stages:</div>
<div class="preset_text_number">${Object.keys(preset.stages).length}</div>
</div>
<div class="number_failure stage_preset_information">
<div class="preset_text">number of f for failure:</div>
<div class="preset_text_number">${preset.f_for_failure}</div>
</div>
<div class="last_edited">last edited: ${preset.last_edited}</div>
<img src="../../assets/elements/cross.png" alt="remove preset" class="remove_preset">
<img src="../../assets/elements/cross_inverted.png" alt="remove preset" class="remove_preset_inverted" id="remove_preset_inverted_${preset.stage_preset_number}">`
}
});
}
updatePreset(stage_presets)
function presetRemove(e) {
console.log("successfully ran the function!")
}
document.querySelector('#remove_preset_inverted_1').addEventListener('click', presetRemove)
* {
margin: 0;
padding: 0;
font-family: 'Arial';
box-sizing: border-box;
}
body {
font-weight: 200;
font-size: 0.46vh;
background-color: #cde480;
height: 100vh;
width: 100vw;
overflow: hidden;
}
.stage_preset_selection_container {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
height: 100vh;
width: 100vw;
transition: transform .5s;
}
.stage_preset_selection_column {
display: flex;
flex-direction: column;
justify-content: space-around;
align-items: center;
}
.preset_number {
font-size: 11em;
color: #394a00;
font-weight: 400;
letter-spacing: .1em;
user-select: none;
transition: color .3s;
}
.preset_title {
font-size: 10em;
color: #394a00;
letter-spacing: .1em;
margin-bottom: 3vh;
user-select: none;
transition: color .3s;
}
.preset_text_number,
.preset_text {
font-size: 6em;
color: #727f45;
letter-spacing: .1em;
user-select: none;
}
.last_edited {
font-size: 4em;
color: #727f45;
letter-spacing: .1em;
margin-top: 3vh;
user-select: none;
white-space: nowrap;
}
.empty_preset_title {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, 0%);
font-size: 10em;
color: #727f45;
font-style: italic;
letter-spacing: .1em;
user-select: none;
white-space: nowrap;
}
.stage_preset_information {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.stage_preset {
position: relative;
border: 0.56vh solid #394a00;
border-radius: 4.63vh;
width: 45vw;
height: 42vh;
padding: 3vh 12vh 4vh 4vh;
margin: 2vh 3vh;
cursor: pointer;
box-shadow: 0 1.5vh 1.7vh rgba(0, 0, 0, 0.3);
user-select: none;
transition: all .3s;
}
.stage_preset:hover {
background-color: #394a00;
transform: translateY(-1vh);
box-shadow: 0 2.5vh 2.7vh rgba(0, 0, 0, 0.4);
}
.stage_preset:active {
background-color: #212b00;
border: 0.56vh solid #212b00;
transform: translateY(-.5vh);
box-shadow: 0 2vh 2.2vh rgba(0, 0, 0, 0.35);
}
.stage_preset:hover > .remove_preset_inverted {
opacity: 100%;
display: block;
}
.stage_preset:active > .preset_title,
.stage_preset:active > .preset_number,
.stage_preset:hover > .preset_title,
.stage_preset:hover > .preset_number {
color: #cde480;
}
.toggle_empty_preset {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -100%);
}
.remove_preset {
position: absolute;
top: 14%;
left: 92%;
transform: translate(-50%, -50%);
width: 3.33vh;
height: 3.33vh;
cursor: pointer;
transition: all 0.3s;
}
.remove_preset_inverted {
position: absolute;
top: 14%;
left: 92%;
transform: translate(-50%, -50%);
width: 3.33vh;
height: 3.33vh;
cursor: pointer;
opacity: 0;
display: none;
transition: all 0.3s;
}
.remove_preset_inverted:hover {
transform: translate(-50%, -60%);
}
.remove_preset_inverted:active {
transform: translate(-50%, -55%)
}
.stage_preset_selected {
transform: translateX(-100%);
}
.preset_setup_container {
position: absolute;
display: flex;
top: 0;
left: 0;
transform: translateX(100vw);
transition: all 0.5s;
}
.preset_setup_selected {
transform: translateX(0);
}
<!DOCTYPE html>
<html lang="en">
<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">
</head>
<body>
<div class="stage_preset_selection_container">
<div class="stage_preset_selection_column">
<div class="stage_preset" id="stage_preset_1">
<!-- <div class="preset_number">Preset 1</div>
<div class="preset_title">title of the preset</div>
<div class="questions_stage stage_preset_information">
<div class="preset_text">questions per stage:</div>
<div class="preset_text_number">5</div>
</div>
<div class="number_stages stage_preset_information">
<div class="preset_text">number of stages:</div>
<div class="preset_text_number">13</div>
</div>
<div class="number_failure stage_preset_information">
<div class="preset_text">number of f for failure:</div>
<div class="preset_text_number">3</div>
</div>
<div class="last_edited">last edited: 30-06-2021 14:51</div>
<img src="../../assets/elements/cross.png" alt="remove preset" class="remove_preset">
<img src="../../assets/elements/cross_inverted.png" alt="remove preset" class="remove_preset_inverted"> -->
<!-- <div class="preset_number toggle_empty_preset">Preset 2</div>
<div class="empty_preset_title">Empty preset</div> -->
</div>
<div class="stage_preset" id="stage_preset_2"></div>
</div>
<div class="stage_preset_selection_column">
<div class="stage_preset" id="stage_preset_3"></div>
<div class="stage_preset" id="stage_preset_4"></div>
</div>
</div>
</body>
</html>
答案肯定是通过事件委托附加侦听器,而不是直接附加到动态元素上。这将使您不必在每个“#remove_preset_inverted[num]”上放置一个新的侦听器。
您可以简单地在初始页面加载中执行此操作
window.addEventListener('load', () => {
document.addEventListener('click', (e) => {
if (e.target.classList.contains('remove_preset_inverted')) {
// this is one of those elements. If you need to test for the id:
let id = e.target.getAttribute('id').split('remove_preset_inverted_')[1];
}
})
})