В настоящее время я работаю над эскизом проекта Odin. Вот код, который я придумал.
const container = document.querySelector(".container");
const input = document.querySelector("input");
const submitBtn = document.querySelector("button");
function createGrid() {
let value=input.value;
for (let i = 0; i < value; i++) {
const createDivRow = document.createElement("div");
createDivRow.classList.add("gridrow")
createDivRow.textContent = i;
container.appendChild(createDivRow);
}
}
function createGridItems() {
let value = input.value;
for (let i = 0; i < value; i++) {
const divRow = document.querySelectorAll(".gridrow");
const createDivItem = document.createElement("div");
createDivItem.textContent = "aa";
divRow.appendChild(createDivItem);
}
}
submitBtn.addEventListener("click", createGrid);
submitBtn.addEventListener("click", createGridItems);
В функции createGrid() я стремлюсь создать n элементов div (n — это пользовательский ввод из текстового поля ввода), что мне удалось. Результатом стало n элементов div с class="gridrow" в контейнере.
В функции createGridItems() я хотел бы поместить одинаковое количество элементов div "n" в каждую строку .gridrow (которую я задал переменной divRow).
Я попробовал объявить const divRow = document.querySelector(".gridRow"), и в результате в ПЕРВОМ div .gridrow появилось n элементов div, что почти то, что я хотел.
Итак, я решил объявить const divRow = document.querySelectorAll(".gridrow") таргетингом на все созданные мной .gridrow и поместить n элементов div в КАЖДЫЙ div .gridrow. В результате все, что я получил, это просто пустое количество элементов .gridrow без нужных элементов.
Может ли кто-нибудь сказать мне, где я ошибся? Я был уверен, что приведенный выше код будет работать, потому что я уже нацелился на все элементы div .divrow, когда объявлял divRow = document.querySelectorAll(".gridrow").
Спасибо!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Это потому, что querySelectorAll() возвращает статический (не живой) NodeList:
Метод Document
querySelectorAll()возвращает статический (не живой) NodeList представляет собой список элементов документа, соответствующих указанная группа селекторов.
Хотя NodeList не равен массиву, он называется array-alike, но когда он статичен, любые изменения в DOM не повлияют на содержимое коллекции узлов.
Статические списки узлов
В других случаях NodeList является статическим, и любые изменения в DOM не влияют на содержимое коллекции. Вездесущий метод document.querySelectorAll() возвращает статический Список узлов.
Тем не менее, вам нужно сначала преобразовать NodeList в массив, затем внести изменения и, наконец, внедрить свой html, и самый простой способ преобразовать его в массив — использовать оператор распространения, например:
function createGridItems() {
let value = input.value;
for (let i = 0; i < value; i++) {
// wrap with brackets, then use spread
const divRow = [...document.querySelectorAll(".gridrow")];
const createDivItem = document.createElement("div");
createDivItem.textContent = "aa";
// use push instead of appendChild
divRow.push(createDivItem);
// now loop throgh divrow
let html = "";
divRow.forEach(el=> html+=el.outerHTML);
document.querySelector("WHATEVER_SELECTOR_YOU_WANT").innerHTML = html
}
}
вы все еще вызываете appendChild через массив
Я опубликовал свой собственный ответ, потому что вы не поняли суть... теперь вы просто помещаете элементы в массив, не связанный с dom... какова его цель??
привет, я попробовал запустить ваш ответ, но он все равно не работает. Я попробовал погуглить, как превратить список узлов в массив, и нашел метод Array.from().
я попытался превратить divRow в массив с помощью const arrayDivRow = Array.from(divRow), а затем попытался добавить arrayDivRow с помощью createDivItem, но это все равно не сработало. есть идеи, где что-то пошло не так?
благодаря @DiegoD отметил, что да, я создал массив, но затем не вставил его в html, я отредактировал свой ответ, чтобы это исправить.
document.querySelectorAll возвращает NodeList (набор элементов).
Если вы проверили консоль JavaScript, ваш код выдает ошибку при попытке .appendChild перебрать коллекцию.
Вместо этого вам нужно было перебрать эту коллекцию и для каждого элемента (являющегося .gridrow) добавить туда несколько элементов.
https://developer.mozilla.org/en-US/docs/Web/API/NodeList
Примечание. Хотя NodeList не является массивом, его можно перебирать. над ним с помощью forEach(). Его также можно преобразовать в настоящий массив, используя Массив.из().
Это быстрая демонстрация:
const container = document.querySelector(".container");
const input = document.querySelector("input");
const submitBtn = document.querySelector("button");
function createGrid() {
const value = input.value;
for (let i = 0; i < value; i++) {
const createDivRow = document.createElement("div");
createDivRow.classList.add("gridrow")
createDivRow.textContent = i;
container.appendChild(createDivRow);
}
}
function createGridItems() {
const value = input.value;
//here you select the rows as .gridrow elements
const divRows = document.querySelectorAll(".gridrow");
//iterate over each one of them
divRows.forEach(divRow =>{
//and append to it a new div for as many times as the value fetched from the input element
for(let i=0;i < value; i++){
const createDivItem = document.createElement("div");
createDivItem.textContent = "aa";
divRow.appendChild(createDivItem);
}
});
}
submitBtn.addEventListener("click", createGrid);
submitBtn.addEventListener("click", createGridItems);.gridrow{
border: solid 1px;
margin-top: 1em;
}
.gridrow > div {
border: solid 1px red;
margin-left: 1em;
display: inline-block;
}<div class = "container"></div>
<input type = "text">
<button>submit</button>И, наконец, поскольку в комментариях возникла проблема с производительностью, вот тест производительности, показывающий разницу во времени для каждого решения:
const numElements = 1000;
function addDivsOneByOne(containerId) {
const container = document.getElementById(containerId);
for (let i = 0; i < numElements; i++) {
const div = document.createElement('div');
div.textContent = `${i + 1}`;
container.appendChild(div);
}
}
function addDivsInBatch(containerId) {
const container = document.getElementById(containerId);
const fragment = document.createDocumentFragment();
for (let i = 0; i < numElements; i++) {
const div = document.createElement('div');
div.textContent = `${i + 1}`;
fragment.appendChild(div);
}
container.appendChild(fragment);
}
function addDivsUsingInnerHTML(containerId) {
const container = document.getElementById(containerId);
let html = '';
for (let i = 0; i < numElements; i++) {
html += `<div>${i + 1}</div>`;
}
container.innerHTML = html;
}
function runBenchmark() {
document.getElementById('container1').innerHTML = '';
document.getElementById('container2').innerHTML = '';
document.getElementById('container3').innerHTML = '';
const results = [];
// Measure addDivsOneByOne
let start = performance.now();
addDivsOneByOne('container1');
let end = performance.now();
results.push(`addDivsOneByOne took ${end - start} milliseconds.`);
// Measure addDivsInBatch
start = performance.now();
addDivsInBatch('container2');
end = performance.now();
results.push(`addDivsInBatch took ${end - start} milliseconds.`);
// Measure addDivsUsingInnerHTML
start = performance.now();
addDivsUsingInnerHTML('container3');
end = performance.now();
results.push(`addDivsUsingInnerHTML took ${end - start} milliseconds.`);
// Display results
document.getElementById('results').innerHTML = results.join('<br>');
}.container {
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
}
.container div {
margin: 2px 0;
}<div id = "results"></div>
<div class = "container" id = "container1"></div>
<div class = "container" id = "container2"></div>
<div class = "container" id = "container3"></div>
<div>
<button onclick = "runBenchmark()">Run Benchmark</button>
</div>Привет! Большое спасибо, это сработало! Для ясности: когда я запускаю divRows с помощью forEach(), он рассматривает divRows как массив, а не как nodeList? Вот почему это сработало?
Здесь нужно добавить только одну вещь: вы добавляете дочерний элемент на каждой итерации, что может повлиять на производительность в зависимости от количества элементов. Вместо этого создайте временную переменную, которая собирает все элементы, а затем добавьте ее один раз.
@AndreyWidjaja Я отредактировал ответ, добавив ссылку на страницу NodeList mdn... буквально заявив, что, несмотря на то, что он не является массивом, он все еще доступен для повторения. И, кстати, при добавлении таких дочерних элементов в цикл проблем с производительностью не возникает. Чтобы увидеть разницу в добавлении их всех сразу, вместо того, чтобы делать это по одному, потребуется эталон, но на самом деле это звучит как стрижка волос пополам, когда величина порядка сотен.
@DiegoD ах, я вижу, я почитаю эту страницу mdn! еще немного туманно в отношении концепции..
@MHDLaaAlhaj Я пока не совсем уверен, как это сделать. Я работаю над проектом Odin и только что закончил практиковаться в циклах, так что я использовал именно это. В любом случае спасибо за вклад!
@DiegoD Я не говорил, что NodeList не является итеративным, я даже упомянул в своем ответе ту же ссылку, которую вы уже прокомментировали. мой комментарий был о выступлении. Вы должны знать, что всякий раз, когда есть шанс повысить производительность, даже если этот шанс составляет всего лишь 1%, мы должны пойти на это, особенно если для достижения этой цели не будет внесено никаких огромных изменений. Если вы действительно не знаете о влиянии этого на производительность, я рекомендую вам прочитать больше о Repaint и Reflow.
да, вы правы, и я знал, что есть разница в производительности... но, честно говоря, я был уверен, что включение парсера html при использовании innerHTML замедлит процесс... Я ошибался. В любом случае я добавил тест, который покажет, учитывая произвольное количество добавляемых элементов (по умолчанию 1000), покажет время, необходимое для каждого из этих трех разных подходов.
@DiegoD Вы приложили огромные усилия, спасибо за объяснение!
NodeList(коллекцию элементов). Вы проверяли консоль JavaScript? ваш код выдает ошибку при попытке.appendChildперебрать коллекцию.