Я пытаюсь динамически добавить созданный мной пользовательский элемент, но он не генерирует их должным образом.
объявление элемента div:
class Item extends HTMLElement {
constructor() {
super();
this.src = this.getAttribute("src");
this.link = this.getAttribute("href");
this.attachShadow({ mode: 'open'});
this.text = this.textContent.trim();
this.shadowRoot.innerHTML = `
<style>/* Styles excluded */</style>
<div>
<a href='${this.link}'>
<div class = "bg">
<img src = "${this.src}" alt = "${this.text}">
</div>
<p>${this.text}</p>
</a>
</div>
`;
}
}
customElements.define('div-item', Item);
Генерация Javascript:
function createDivItems() {
// Get all elements with the class name "row"
var rows = document.getElementsByClassName("row");
// Iterate over each row element
for (var j = 0; j < rows.length; j++) {
var row = rows[j];
// Remove all existing div-item elements from the row
row.innerHTML = '';
// Create and add elements based on the window width
for (var i = 0; i < (window.innerWidth - 60); i += 120) {
// Create a new custom element
var elem = document.createElement("div-item", {"src": '<?php echo "assets/not found.png"; ?>', "href": '<?php echo "/newPage.php"; -- placeholders for implementing the shop system ?>'});
// Set attributes for the custom element
elem.setAttribute("src", '<?php echo "assets/not found.png"; ?>');
elem.setAttribute("href", '<?php echo "/newPage.php"; ?>');
elem.innerHTML = 'not used.'
// Append the custom element to the current row
row.appendChild(elem);
}
}
}
Я думал, что это создаст значки и текст, но он просто создает пустой квадратный контур (из удаленного CSS).
Я задержал создание пользовательского тега, и он сгенерировал их правильно, но когда я изменил размер, он снова стал пустым квадратом.
По сути, я думаю, что когда я создаю тег, он перестает проверять атрибуты, поэтому мне нужно устанавливать атрибуты при создании элемента, а не после него.
@tacoshy нет преимуществ forEach и несколько недостатков.
@Evert Читабельность превосходит производительность в 99% случаев.
@connexo да, это один из недостатков. Я согласен, что производительность, вероятно, менее важна.



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


Конструктор вызывается внутри вызова createElement() (или во время обновления, если элемент был вставлен парсером).
Таким образом, к моменту вызова метода setAttribute() конструктор уже вызван и тень вашего элемента уже построена без значений атрибутов.
Вместо этого вы хотите скрыть содержимое вашего элемента во время его linkedCallback:
class Item extends HTMLElement {
connectedCallback() {
this.src = this.getAttribute("src");
this.link = this.getAttribute("href");
this.attachShadow({ mode: 'open'});
this.text = this.textContent.trim();
this.shadowRoot.innerHTML = `
<style>/* Styles excluded */</style>
<div>
<a href='${this.link}'>
<div class = "bg">
<img src = "${this.src}" alt = "${this.text}">
</div>
<p>${this.text}</p>
</a>
</div>
`;
}
}
customElements.define('div-item', Item);
function createDivItems() {
// Get all elements with the class name "row"
var rows = document.getElementsByClassName("row");
// Iterate over each row element
for (var j = 0; j < rows.length; j++) {
var row = rows[j];
// Remove all existing div-item elements from the row
row.innerHTML = '';
// Create and add elements based on the window width
for (var i = 0; i < (window.innerWidth - 60); i += 120) {
// Create a new custom element
// Note: the options argument of createElement only takes an 'is' property
var elem = document.createElement("div-item");
// Set attributes for the custom element
elem.setAttribute("src", "assets/not found.png");
elem.setAttribute("href", "/newPage.php");
elem.innerHTML = 'not used.'
// Append the custom element to the current row
row.appendChild(elem);
}
}
}
createDivItems();<div class = "row"></div>Кайидо прав, вы не можете использовать constructor для выполнения (некоторых) операций DOM, когда вы это делаетеcreateElement("<div-item"), потому что этот элемент находится в памяти и создается только в DOM
когда ты это сделаешь appendChild(elem)
appendChild тоже не то, что вы хотите; используйте современный append (добавляет несколько узлов DOM, но не поддерживается в старом добром Internet Explorer)
Поскольку вы не хотите вызывать append(Child) внутри цикла, каждый вызов, вероятно, будет вызывать перерисовку и перекомпоновку DOM.
Нижеприведенный код я сосредоточил внимание на болевых точках; вы можете добавить свои собственные материалы
Примечание: у connectedCallback есть потенциальная проблема с DOM при попытке прочитать LightDOM,
нет в этом фрагменте.
98 из 100 разработчиков ошибаются, потому что на 100% не знают, что делает connectedCallback
Смотрите моего блогбоста
<div id = "row1" class = "row">FOO</div>
<div id = "row2" class = "row">BAR</div>
<div id = "row3" class = "row">BAZ</div>
<script>
customElements.define('div-item', class extends HTMLElement {
connectedCallback() {
let src = this.getAttribute("src");
this.attachShadow({mode:'open'})
.innerHTML = `<img src = "${src}" style = "width:40px">` + this.textContent.trim();
}
});
var rows = [...document.getElementsByClassName("row")];
rows.map(row => {
row.innerHTML = ''; // delete FOO, BAR in row
const length = Math.ceil((window.innerWidth - 60) / 120);
console.info(row.id, "add", length, "div-items");
const items = Array(length).fill(0).map((_, index) => {
let elem = document.createElement("div-item");
elem.setAttribute("src", "//we-are-all.github.io/sheep.svg");
elem.append(row.id, "-", index);
return elem;
});
row.append(...items); // append to row ONCE!!
})
</script>«каждый вызов, вероятно, приведет к перерисовке и перекомпоновке DOM». это было бы верно только в том случае, если конструктор действительно запросил вычисленные стили на странице, и если это так, скорее всего, им нужно, чтобы они были в DOM.
Не вызывают ли новые узлы DOM сдвиг макета?
Пока стили не будут пересчитаны.
Не используйте map, если отображаемый массив вас не интересует. Тогда используйте forEach.
Увы, мое внимание часто сосредоточено на лучшем GZIP-коде; это моя единственная мотивация использовать карту. Да, я знаю, это глупо, но это как зависимость, я легко могу потратить целый день на то, чтобы избавиться еще от 2-х байтов........... dev.to/dannyengelman/…
Примечание: используйте
querySelectorAll, что позволяет использоватьforEachвместо циклаfor. Более производительный вместо вложенных циклов for.