自定义元素未设置/获取属性

kej*_*eja 3 javascript attributes nested custom-element

如果我创建两个自定义元素并在另一个元素内创建其中一个,则这些属性不适用于第一个元素的新子元素。

class Bar extends HTMLElement {
  constructor() {
    super();
    const val = this.getAttribute('val') || 'no value';

    const shadow = this.attachShadow({mode: 'open'});
    const wrapper = document.createElement('div');
    wrapper.innerHTML = `
      <div class='bar'>
      	<span>${val}</span>
      </div>
    `;

    shadow.appendChild(wrapper);
  }
}
customElements.define('x-bar', Bar);

class Foo extends HTMLElement {
  constructor() {
    super();
    const loop = this.getAttribute('loop') || 10;

    const shadow = this.attachShadow({mode: 'open'});
    const wrapper = document.createElement('div');
    
    for(let i=0; i<loop; i++){
    	const b = document.createElement('x-bar');
        b.setAttribute('val', `value #${i}`);
      
        wrapper.appendChild(b);
    }

    shadow.appendChild(wrapper);
  }
}
customElements.define('x-foo', Foo);
Run Code Online (Sandbox Code Playgroud)
<x-foo loop='3'></x-foo>
Run Code Online (Sandbox Code Playgroud)

我期望我的输出是

值#0

价值#1

值#2

因为我已经这样设置了 attrb.setAttribute('val', value #${i});

但我得到了 3xno value

有什么意见可以解释为什么会这样吗?和/或如何解决它,谢谢!

Int*_*lia 6

大多数人不知道 Web 组件构造函数的规则:

\n\n

以下是官方文档:

\n\n

https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance

\n\n

总结是:

\n\n

你的构造函数代码:

\n\n
    \n
  • 必须对\xc2\xa0super()\xc2\xa0进行无参数调用作为构造函数中的第一个语句。
  • \n
  • 构造函数中的任何位置都不能有\xc2\xa0return\xc2\xa0语句。
  • \n
  • 不得调用 document.write()\xc2\xa0 或 \xc2\xa0document.open()。
  • \n
  • 不得检查元素的属性。
  • \n
  • 不得更改或添加任何属性或子项。
  • \n
\n\n

一般来说,构造函数应该用于设置初始状态和默认值,并设置事件侦听器和可能的\xc2\xa0shadow 根。

\n\n

总的来说,我同意@TJ Crowder,但我会对该Bar对象进行一个小修改:

\n\n

\r\n
\r\n
class Bar extends HTMLElement {\r\n  constructor() {\r\n    super();\r\n    this.attachShadow({mode: \'open\'});\r\n  }\r\n  \r\n  static get observedAttributes() {\r\n    // Indicate that we want to be notified\r\n    // when the `val` attribute is changed\r\n    return [\'val\'];\r\n  }\r\n  \r\n  connectedCallback() {\r\n    // Render the initial value\r\n    // when this element is placed into the DOM\r\n    render(this.getAttribute(\'val\'));\r\n  }\r\n  \r\n  attributeChangedCallback(attrName, oldVal, newVal) {\r\n    if (oldVal != newVal) {\r\n      // If the value for the `val` attribute has changed\r\n      // then re-render this element\r\n      render(newVal);\r\n    }\r\n  }  \r\n  \r\n  render(val = \'no value\') {\r\n    this.shadowRoot.innerHTML = `\r\n      <div class=\'bar\'>\r\n      \t<span>${val}</span>\r\n      </div>\r\n    `;\r\n  }\r\n}\r\n\r\ncustomElements.define(\'x-bar\', Bar);
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

attributeChangedCallback这使用了和的标准observedAttributes。虽然覆盖setAttribute功能有效,但它并不能保证未来的发展。如果将来 APIsetAttribute发生变化,那么您需要记住修复您的组件。使用许多组件来执行此操作会导致开发人员背负大量债务。

\n\n

\r\n
\r\n
class Bar extends HTMLElement {\r\n  constructor() {\r\n    super();\r\n    this.attachShadow({mode: \'open\'});\r\n    // Render the blank DOM\r\n    this.shadowRoot.innerHTML = \'<div class="bar"><span>no value</span><div>\';\r\n    this._span = this.shadowRoot.querySelector(\'span\');\r\n  }\r\n  \r\n  static get observedAttributes() {\r\n    // Indicate that we want to be notified\r\n    // when the `val` attribute is changed\r\n    return [\'val\'];\r\n  }\r\n  \r\n  attributeChangedCallback(attrName, oldVal, newVal) {\r\n    if (oldVal != newVal) {\r\n      // If the value for the `val` attribute has changed\r\n      // then insert the value into the `<span>`\r\n      this._span.textContent = newVal || \'no value\';\r\n      // OR: this._span.innerHTML = newVal || \'no value\';\r\n      // But make sure someone has not tried to hit you\r\n      // with a script attack.\r\n    }\r\n  }\r\n  \r\n  get val() {\r\n    return this._span.textContent;\r\n  }\r\n  set val(newVal) {\r\n    if (newVal == null || newVal === false || newVal === \'\') {\r\n      this.removeAttribute(\'val\');\r\n    }\r\n    else {\r\n      this.setAttribute(\'val\', newVal);\r\n    }\r\n  }\r\n}\r\n\r\ncustomElements.define(\'x-bar\', Bar);
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

第二种方法不会重新渲染整个 DOM,它只是将修改后的属性值插入到<span>

\n\n

它还提供属性,以便您可以通过属性以及 JavaScript 设置值:

\n\n
var el = document.querySelector(\'x-bar\');\nif (el) {\n  el.val = "A New String";\n  setTimeout(()=>el.val = \'\';,2000);\n}\n
Run Code Online (Sandbox Code Playgroud)\n