如何访问 WebComponent 的属性?

How to access attribute of a WebComponent?

我正在尝试来自 MDN 的自定义 Web 组件示例。 所以我以这段代码结束

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') returns 未定义。 我 运行 它在 Firefox 本地。 有人可以解释一下这个例子有什么问题吗?

是的,在构造阶段没有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>

constructor 阶段,还没有 DOM。 connectedCallback 是在Web 组件被放入DOM 时调用的,这时你就可以访问它了。使用 connectedCallback 进行 DOM 操作和事件监听。