无法从其构造函数访问自定义元素的属性

Cannot access attributes of a custom element from its constructor

我正在尝试使用自定义元素 API 创建一个 polyfill,用于游戏内浏览器引擎用来显示按钮和类似元素的自定义元素。 但是,我似乎无法从构造函数中访问元素的属性(例如 src、href ...)。

这是一个例子:

class KWButton extends HTMLElement {
  constructor() {
    super();
    var attributes = this.attributes;
    var shadow = this.attachShadow({
      mode: 'open'
    });
    var img = document.createElement('img');
    img.alt = this.getAttribute('text'); // the getAttribute call returns null
    img.src = this.getAttribute('src'); // as does this one
    img.width = this.getAttribute('width'); // and this
    img.height = this.getAttribute('height'); // and this
    img.className = 'vivacity-kwbutton'; // this works fine
    shadow.appendChild(img);
    img.addEventListener('click', () => {
      window.location = this.getAttribute('href'); // this works perfectly fine
    });
  }
}
customElements.define('kw-button',
  KWButton);
<kw-button src="https://placekitten.com/g/198/39" width="198" height="39" icon_src="https://placekitten.com/g/34/32" icon_width="34" icon_height="32" href="https://placekitten.com/" text="placekiten" color="#ffffff" size="18"></kw-button>

您无法访问具有 querySelector()appendChild() 的元素 DOM 树以及 constructor() 中具有 getAttribute()setAttribute() 的属性.

因为调用时constructor()自定义元素还没有内容

你应该在 connectedCallback() 方法中推迟它,这样就没问题了。

来自the specs

The element must not gain any attributes or children, as this violates the expectations of consumers who use the createElement or createElementNS methods.

In general, work should be deferred to connectedCallback as much as possible

更新 截至 12me21 更正:

  • 如果在 HTML 中解析 之前 注册/定义了元素,则属性将不可用
  • 如果这些顺序不同(解析 HTML 为未知,然后定义/升级)- 他们将

总而言之,我现在要说的是,由于这是不确定的,因此,正如规范所警告的那样,我绝对不会访问自定义元素 c~tor 中的任何内容,除了class' 自己的定义等。


虽然我发誓我曾经看过那个规范(@Supersharp 提到的那个),但现在:

    允许
  • 检查 属性(在 Chrome、Firefox 和 Safari 上对我有用),所以 getAttribute OKAY
  • 属性的
  • 突变 正如预期的那样是禁止的

好吧,也许我们确实应该将 'gain' 理解为专门指突变。

可以说 - 等等,但如果元素无法获得任何属性 - 显然没有什么可检查的。好吧,以下代码片段适用于我(在任何浏览器上):

class A extends HTMLElement {
  constructor() {
    super();
    console.log(this.getAttribute('data-some'));
  }
}

globalThis.customElements.define('x-a', A);

const e = document.createElement('x-a');
// console: null

const t = document.createElement('div');
t.innerHTML = '<x-a data-some="test"></x-a>';
// console: test

CodePen