Включите атрибуты в document.createElement для пользовательских элементов

Я пытаюсь динамически добавить созданный мной пользовательский элемент, но он не генерирует их должным образом.

объявление элемента 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).

Я задержал создание пользовательского тега, и он сгенерировал их правильно, но когда я изменил размер, он снова стал пустым квадратом.

По сути, я думаю, что когда я создаю тег, он перестает проверять атрибуты, поэтому мне нужно устанавливать атрибуты при создании элемента, а не после него.

Примечание: используйте querySelectorAll, что позволяет использовать forEach вместо цикла for. Более производительный вместо вложенных циклов for.

tacoshy 05.06.2024 04:35

@tacoshy нет преимуществ forEach и несколько недостатков.

Evert 05.06.2024 05:05

@Evert Читабельность превосходит производительность в 99% случаев.

connexo 13.06.2024 07:37

@connexo да, это один из недостатков. Я согласен, что производительность, вероятно, менее важна.

Evert 13.06.2024 17:26
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
4
76
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Конструктор вызывается внутри вызова 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.

Kaiido 07.06.2024 06:59

Не вызывают ли новые узлы DOM сдвиг макета?

Danny '365CSI' Engelman 07.06.2024 11:36

Пока стили не будут пересчитаны.

Kaiido 08.06.2024 01:14

Не используйте map, если отображаемый массив вас не интересует. Тогда используйте forEach.

connexo 13.06.2024 07:38

Увы, мое внимание часто сосредоточено на лучшем GZIP-коде; это моя единственная мотивация использовать карту. Да, я знаю, это глупо, но это как зависимость, я легко могу потратить целый день на то, чтобы избавиться еще от 2-х байтов........... dev.to/dannyengelman/…

Danny '365CSI' Engelman 13.06.2024 09:37

Другие вопросы по теме