Как получить доступ к атрибуту веб-компонента?

#javascript #html #web-component

#javascript #HTML #веб-компонент

Вопрос:

Я пытаюсь привести пример пользовательских веб-компонентов из MDN. Итак, я закончил с этим кодом

 class Info extends HTMLElement
{
    constructor()
    {
        super();

        const shadow = this.attachShadow({mode: 'open'});
        const wrapper = document.createElement('span');
        wrapper.setAttribute('class', 'wrapper');

        const icon = document.createElement('span');
        icon.setAttribute('class', 'icon');
        icon.setAttribute('tabindex', 0);

        const info = document.createElement('span');
        info.setAttribute('class', 'info');

        // Take attribute content and put it inside the info span
        const text = this.getAttribute('data-text');
        info.textContent = text;
        console.log(JSON.stringify(this.attributes['img']));

        // Insert icon
        const img = document.createElement('img');
        img.src = this.hasAttribute('img') ? this.getAttribute('img') : 'img/default.png';
        icon.appendChild(img);

        // Create some CSS to apply to the shadow dom
        const style = document.createElement('style');

        style.textContent = `
            .wrapper {  position: relative;     }
            img {   width: 1.2rem;  }
        `;

        // Attach the created elements to the shadow dom
        shadow.appendChild(style);
        shadow.appendChild(wrapper);
        wrapper.appendChild(icon);
        wrapper.appendChild(info);
    }
}
customElements.define('a-info', Info); 
 <html>
    <head></head>
    <body>
        <a-info img="img/alt.png" data-text="Your card."></a-info>
    </body>
</html> 

Это почти работает. Элемент создается, за исключением this.getAttribute('data-text') возвратов undefined .
Я запускаю его локально в Firefox.
Не мог бы кто-нибудь объяснить, в чем проблема с этим примером, пожалуйста?

Комментарии:

1. Я провел некоторое расследование, и, похоже getAttribute() , возвращает правильное значение при вызове из connectedCallback() .

Ответ №1:

Да, на этапе конструктора нет доступного DOM

смотрите: https://andyogo.github.io/custom-element-reactions-diagram /

И не слишком полагайтесь на официальную документацию, она раздута, а иногда и просто неверна:

 <script>
  class Info extends HTMLElement {
    constructor() {
      let createElement = (name, className) => {
        let el = document.createElement(name);
        if (className) el.classList.add(className);
        return el;
      }
      // yes you can add code *before* super()
      const style = createElement('style');
      style.textContent = `.wrapper {position:relative}img {width: auto}`;
      const wrapper = createElement('span', 'wrapper');
      const icon = createElement('span', 'icon');
      icon.setAttribute('tabindex', 0);

      super() // set AND return this scope
        .attachShadow({mode: 'open'}) // set AND return this.shadowRoot
        .append(style,wrapper);
        
      this.info = createElement('span', 'info');
      this.img = createElement('img');
      icon.append(this.img);
      wrapper.append(icon, this.info);
    }
    connectedCallback() {
      this.info.textContent = this.getAttribute('data-text') || "card?";
      this.img.src = this.getAttribute('img') || 'https://via.placeholder.com/42';
    }
  }
  customElements.define('a-info', Info);
</script>
<a-info></a-info>
<a-info img="https://via.placeholder.com/110" data-text="Card #1"></a-info>
<a-info img="https://via.placeholder.com/120" data-text="Card #2"></a-info> 

Ответ №2:

Во время constructor фазы DOM еще нет. connectedCallback вызывается, когда веб-компонент помещается в DOM, и тогда вы можете получить к нему доступ. Используется connectedCallback для манипуляций с DOM и прослушивания событий.