Я застрял в этой простой манипуляции JS DOM. Ниже приведена моя разметка HTML. Я пытаюсь динамически генерировать отдельные элементы списка с помощью JS.
Моя проблема: каждый отдельный тег Span должен содержать отдельный элемент из массива объектов, но в моем случае один тег span содержит все элементы. Как я могу заставить его работать? Я знаю, что это должно быть что-то очень простое, но я не мог понять, где я здесь не прав?
HTML-код:
<ul class="collection" id="web-book-list">
<li class="collection-item">
<span class="flow-text">item 1</span>
<a href="#!" class="secondary-content"
><i class="small material-icons black-text">visibility</i></a
>
<a href="#!" class="secondary-content"
><i class="small material-icons red-text">delete_forever</i></a
>
</li>
<li class="collection-item">
<span class="flow-text">item 2</span>
<a href="#!" class="secondary-content"
><i class="small material-icons black-text">visibility</i></a
>
<a href="#!" class="secondary-content"
><i class="small material-icons red-text">delete_forever</i></a
>
</li>
</ul>
JS CODE:
let bookList = document.getElementById("web-book-list");
// Create element
let li = document.createElement("li");
let span = document.createElement("span");
let linkA = document.createElement("a");
let linkB = document.createElement("a");
let visible = document.createElement("i");
let deleteBtn = document.createElement("i");
// Add classes to elements
li.className = "collection-item";
span.className = "flow-text";
linkA.className = "secondary-content";
linkB.className = "secondary-content";
visible.className = "small material-icons black-text";
deleteBtn.className = "small material-icons red-text";
// create text nodes
visible.appendChild(document.createTextNode("visibility"));
deleteBtn.appendChild(document.createTextNode("delete_forever"));
linkA.appendChild(visible);
linkB.appendChild(deleteBtn);
//Loop through the webBooks
for (let i = 0; i < webBooks.length; i++) {
console.log(webBooks[i]);
span.innerHTML += webBooks[i].name; // Problem is here!
li.appendChild(span);
li.appendChild(linkA);
li.appendChild(linkB);
bookList.appendChild(li);
}
console.log(bookList);
Вам нужно создать элемент span
для каждой книги в цикле. Вам также необходимо создать li
и ссылки. Когда вы используете appendChild
для добавления элемента, который уже находится в другом месте документа, он перемещается, а не копируется.
Поскольку вы устанавливаете классы для элементов и т.д., cloneNode
простой способ создать отдельные для каждой итерации цикла - использовать cloneNode
:
let bookList = document.getElementById("web-book-list");
// Create element
let li = document.createElement("li");
let span; // *** No need to create one here
let linkA = document.createElement("a");
let linkB = document.createElement("a");
// ...
for (let i = 0; i < webBooks.length; i++) {
console.log(webBooks[i]);
const thisSpan = span.cloneNode(true); // ***
thisSpan.innerHTML = webBooks[i].name; // *** No need for += since we're creating a new span
const thisLi = li.clone(true); // ***
thisLi.appendChild(thisSpan); // ***
thisLi.appendChild(linkA.cloneNode(true)); // ***
thisLi.appendChild(linkB.cloneNode(true)); // ***
bookList.appendChild(thisLi); // ***
}
Я также предлагаю не рассматривать текст как HTML, который вы здесь делаете:
thisSpan.innerHTML = webBooks[i].name;
Если это имя имеет <
в нем (или даже вредоносный контент скрипта), было бы проблемой рассматривать его как HTML. Вместо:
thisSpan.appendChild(document.createTextNode(webBooks[i].name));
appendChild(document.createTextNode(webBooks[i].name));
но потом подумал, что это не помогает, поэтому я попытался использовать innerHTML.
Удалите +=
и добавьте использование bookList.appendChild(li.cloneNode(true));
var bookList = document.getElementById("web-book-list");
// Create element
var li = document.createElement("li");
var span = document.createElement("span");
var linkA = document.createElement("a");
var linkB = document.createElement("a");
var visible = document.createElement("i");
var deleteBtn = document.createElement("i");
// Add classes to elements
li.className = "collection-item";
span.className = "flow-text";
linkA.className = "secondary-content";
linkB.className = "secondary-content";
linkA.href = "#0";
linkB.href = "#0";
visible.className = "small material-icons black-text";
deleteBtn.className = "small material-icons red-text";
// create text nodes
visible.appendChild(document.createTextNode("visibility "));
deleteBtn.appendChild(document.createTextNode("delete_forever"));
linkA.appendChild(visible);
linkB.appendChild(deleteBtn);
//Loop through the webBooks
for (let i = 0; i < 10; i++) {
span.innerHTML = "test"+i+ " "; // Problem is here!
li.appendChild(span);
li.appendChild(linkA);
li.appendChild(linkB);
bookList.appendChild(li.cloneNode(true));
}
<ul class="collection" id="web-book-list">
<li class="collection-item">
<span class="flow-text">item 1</span>
<a href="#!" class="secondary-content"
><i class="small material-icons black-text">visibility</i></a
>
<a href="#!" class="secondary-content"
><i class="small material-icons red-text">delete_forever</i></a
>
</li>
<li class="collection-item">
<span class="flow-text">item 2</span>
<a href="#!" class="secondary-content"
><i class="small material-icons black-text">visibility</i></a
>
<a href="#!" class="secondary-content"
><i class="small material-icons red-text">delete_forever</i></a
>
</li>
</ul>
Не забудьте также href
linkA.href = "#0";
linkB.href = "#0";
Вы пробовали javascript =)?
const bookList = document.getElementById("web-book-list");
const webBooks = [
{name: "wb-1"},
{name: "wb-2"},
{name: "wb-3"},
{name: "wb-4"}
];
for (let i = 0; i < webBooks.length; i++) {
const li = document.createElement('li');
li.className = 'collection-item';
li.innerHTML = '
<span class="flow-text">${webBooks[i].name}</span>
<a href="#!" class="secondary-content">
<i class="small material-icons black-text">visibility</i>
</a>
<a href="#!" class="secondary-content">
<i class="small material-icons red-text">delete_forever</i>
</a>';
bookList.appendChild(li);
}