你真的很亲密。为contentElement 和titleElement 获取undefined 的问题是described in this question's answers,但那里的答案,一般来说,并没有给你最简单的方法来处理你的情况。
见 cmets:
function getElements() {
loadJSON(function(response) {
var elements = JSON.parse(response);
var containerElement = document.getElementById("element");
var entryElement;
var titleElement;
var contentElement;
var deleteElement;
for (var i = 0; i < elements.length; i++) {
// Create a container for the entry; let's give it a class we'll
// use later as well
entryElement = document.createElement("div");
entryElement.className = "entry";
titleElement = document.createElement("h1");
contentElement = document.createElement("p");
deleteElement = document.createElement("button");
// Put these in the entry's container
entryElement.appendChild(titleElement);
entryElement.appendChild(contentElement);
entryElement.appendChild(deleteElement);
titleElement.innerHTML = elements[i].title;
contentElement.innerHTML = elements[i].content;
deleteElement.innerHTML = "Delete";
deleteElement.addEventListener('click', function() {
// Here, `this` refers to the delete button that was clicked;
// remove its parent element:
var parent = this.parentNode;
parent.parentNode.removeChild(parent);
});
// Add the entry to the main container
containerElement.appendChild(entryElement);
}
});
}
另外,无需在addElement 中重新加载 JSON,只需将新元素实时添加到页面即可。事实上,既然我们想在从 JSON 创建元素时和添加新元素时都这样做,让我们把它放在一个函数中,然后重用该函数:
'use strict'
var json = '[{' +
'"title": "Hello World !",' +
'"content": "1111111"' +
'},' +
'{' +
'"title": "Lorem Ipsum",' +
'"content": "22222222"' +
'},' +
'{' +
'"title": "azertyuiop",' +
'"content": "33333333"' +
'}' +
']';
function loadJSON(callback) {
// Simulate the ajax
setTimeout(callback, 200, json);
/*
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'json/elements.json', true);
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
*/
}
function addElement(title, content) {
// Create a container for the entry
var entryElement = document.createElement("div");
entryElement.className = "entry";
// And the things to put in it
var titleElement = document.createElement("h1");
var contentElement = document.createElement("p");
var deleteElement = document.createElement("button");
// Put these in the entry's container
entryElement.appendChild(titleElement);
entryElement.appendChild(contentElement);
entryElement.appendChild(deleteElement);
// You might consider HTML-escaping things, here's how
titleElement.appendChild(document.createTextNode(title));
contentElement.appendChild(document.createTextNode(content));
deleteElement.innerHTML = "Delete";
deleteElement.addEventListener('click', function() {
// Here, `this` refers to the delete button that was clicked;
// remove its parent element:
var parent = this.parentNode;
parent.parentNode.removeChild(parent);
});
// Add the entry to the main container
document.getElementById("element").appendChild(entryElement);
}
function getElements() {
loadJSON(function(response) {
var elements = JSON.parse(response);
for (var i = 0; i < elements.length; i++) {
// Call our reusable function
addElement(elements[i].title, elements[i].content);
}
});
}
function addElementClick() {
// Just call our reusable function
addElement(document.getElementById('newTitle').value, document.getElementById('newContent').value);
}
getElements();
<div id="element"></div>
<div id="newElement">
<input id="newTitle" type="text" value="">
<input id="newContent" type="text" value="">
<button type="button" name="addElement" onclick="addElementClick()">Add</button>
</div>
请注意,我将您原来的 addElement 重命名为 addElementClick 并有一个新的 addElement 函数接受标题和内容作为参数。
如果在某个阶段您想要重建 elements 数组,您可以通过从 DOM 中检索数据来轻松实现:
function getElementsFromUI() {
var elements = [];
document.querySelector(".entry").forEach(function(entryElement) {
elements.push({
title: entryElement.querySelector("h1").innerHTML,
content: entryElement.querySelector("p").innerHTML
});
});
return elements;
}
querySelectorAll 返回的NodeList 最近才得到forEach,但您可以在旧版浏览器上轻松地对其进行 polyfill:
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
Object.defineProperty(NodeList.prototype, "forEach", {
value: Array.prototype.forEach,
configurable: true,
enumerable: true
});
}
现场示例:
'use strict'
var json = '[{' +
'"title": "Hello World !",' +
'"content": "1111111"' +
'},' +
'{' +
'"title": "Lorem Ipsum",' +
'"content": "22222222"' +
'},' +
'{' +
'"title": "azertyuiop",' +
'"content": "33333333"' +
'}' +
']';
if (typeof NodeList !== "undefined" && NodeList.prototype && !NodeList.prototype.forEach) {
Object.defineProperty(NodeList.prototype, "forEach", {
value: Array.prototype.forEach,
configurable: true,
enumerable: true
});
}
function loadJSON(callback) {
// Simulate the ajax
setTimeout(callback, 200, json);
/*
var xobj = new XMLHttpRequest();
xobj.overrideMimeType("application/json");
xobj.open('GET', 'json/elements.json', true);
xobj.onreadystatechange = function() {
if (xobj.readyState == 4 && xobj.status == "200") {
callback(xobj.responseText);
}
};
xobj.send(null);
*/
}
function addElement(title, content) {
// Create a container for the entry
var entryElement = document.createElement("div");
entryElement.className = "entry";
// And the things to put in it
var titleElement = document.createElement("h1");
var contentElement = document.createElement("p");
var deleteElement = document.createElement("button");
// Put these in the entry's container
entryElement.appendChild(titleElement);
entryElement.appendChild(contentElement);
entryElement.appendChild(deleteElement);
// You might consider HTML-escaping things, here's how
titleElement.appendChild(document.createTextNode(title));
contentElement.appendChild(document.createTextNode(content));
deleteElement.innerHTML = "Delete";
deleteElement.addEventListener('click', function() {
// Here, `this` refers to the delete button that was clicked;
// remove its parent element:
var parent = this.parentNode;
parent.parentNode.removeChild(parent);
});
// Add the entry to the main container
document.getElementById("element").appendChild(entryElement);
}
function getElements() {
loadJSON(function(response) {
var elements = JSON.parse(response);
for (var i = 0; i < elements.length; i++) {
// Call our reusable function
addElement(elements[i].title, elements[i].content);
}
});
}
function addElementClick() {
// Just call our reusable function
addElement(document.getElementById('newTitle').value, document.getElementById('newContent').value);
}
function getElementsFromUI() {
var elements = [];
document.querySelectorAll(".entry").forEach(function(entryElement) {
elements.push({
title: entryElement.querySelector("h1").innerHTML,
content: entryElement.querySelector("p").innerHTML
});
});
return elements;
}
document.getElementById("btnShow").addEventListener("click", function() {
console.log(getElementsFromUI());
});
getElements();
.as-console-wrapper {
max-height: 100% !important;
}
<input type="button" id="btnShow" value="Show Elements">
<div id="element"></div>
<div id="newElement">
<input id="newTitle" type="text" value="">
<input id="newContent" type="text" value="">
<button type="button" name="addElement" onclick="addElementClick()">Add</button>
</div>
或者,您可以保留 elements 数组的副本,并确保您同时删除条目的 DOM 结构和删除条目,并且类似地确保并行完成添加,但是随后您正在编写代码来维护两个事物列表,这几乎不可避免地会导致更新一个而忘记更新另一个。各种“实时绑定”库试图通过让您维护您的元素数组然后基于它更新 DOM 来提供帮助,例如 Knockout、Vue、React、Angular 和其他十几个。 (有些非常简单,很容易融入任何项目;其他的则复杂得多,采用“你用我们的方式做你的应用程序”的方法。:-))对于任何不平凡的事情,可能值得看看类似的东西。