[英]custom elements not setting/getting attributes
如果我创建了两个自定义元素,并在另一个元素中创建了其中一个,则该属性不适用于第一个元素的新子元素。
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);
<x-foo loop='3'></x-foo>
我希望我的输出是
值#0
价值#1
价值#2
因为我已经像这样设置了attr b.setAttribute('val', value #${i});
但是我no value
3倍的no value
为什么要输入任何信息? 和/或解决方法,谢谢!
大多数人不了解Web组件的构造函数的规则:
这是官方文档:
https://w3c.github.io/webcomponents/spec/custom/#custom-element-conformance
摘要是:
您的构造函数代码:
通常,应使用构造函数来设置初始状态和默认值,并设置事件侦听器以及可能的影子根。
总的来说,我同意@TJ Crowder,但是我将对Bar
对象做一个小的修改:
class Bar extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); } static get observedAttributes() { // Indicate that we want to be notified // when the `val` attribute is changed return ['val']; } connectedCallback() { // Render the initial value // when this element is placed into the DOM render(this.getAttribute('val')); } attributeChangedCallback(attrName, oldVal, newVal) { if (oldVal != newVal) { // If the value for the `val` attribute has changed // then re-render this element render(newVal); } } render(val = 'no value') { this.shadowRoot.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; } } customElements.define('x-bar', Bar);
这使用了attributeChangedCallback
和observedAttributes
的标准。 尽管覆盖setAttribute
功能有效,但这并不是未来的证明。 如果将来更改setAttribute
的API,则需要记住要修复您的组件。 而使用许多组件执行此操作会增加开发人员的债务。
class Bar extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); // Render the blank DOM this.shadowRoot.innerHTML = '<div class="bar"><span>no value</span><div>'; this._span = this.shadowRoot.querySelector('span'); } static get observedAttributes() { // Indicate that we want to be notified // when the `val` attribute is changed return ['val']; } attributeChangedCallback(attrName, oldVal, newVal) { if (oldVal != newVal) { // If the value for the `val` attribute has changed // then insert the value into the `<span>` this._span.textContent = newVal || 'no value'; // OR: this._span.innerHTML = newVal || 'no value'; // But make sure someone has not tried to hit you // with a script attack. } } get val() { return this._span.textContent; } set val(newVal) { if (newVal == null || newVal === false || newVal === '') { this.removeAttribute('val'); } else { this.setAttribute('val', newVal); } } } customElements.define('x-bar', Bar);
第二种方法不会重新呈现整个DOM,它只是将修改后的属性值插入<span>
标记中。
它还提供了属性,因此您可以通过属性以及JavaScript来设置值:
var el = document.querySelector('x-bar');
if (el) {
el.val = "A New String";
setTimeout(()=>el.val = '';,2000);
}
直到构造函数被调用后 ,才设置属性。 注意记录:
class Bar extends HTMLElement { constructor() { super(); const val = this.getAttribute('val') || 'no value'; console.log("In constructor, val = " + val); 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++){ console.log("Constructing..."); const b = document.createElement('x-bar'); console.log("Setting attribute"); b.setAttribute('val', `value #${i}`); wrapper.appendChild(b); } shadow.appendChild(wrapper); } } customElements.define('x-foo', Foo);
<x-foo loop='3'></x-foo>
您需要将渲染逻辑移出构造函数,以便可以考虑构造后设置的属性。 也许通过重写setAttribute
:
class Bar extends HTMLElement { constructor() { super(); const shadow = this.attachShadow({mode: 'open'}); this.wrapper = document.createElement('div'); this.render(); // Though calling methods from the constructor isn't ideal shadow.appendChild(this.wrapper); } setAttribute(name, value) { super.setAttribute(name, value); if (name === "val") { this.render(); } } render() { const val = this.getAttribute('val') || 'no value'; this.wrapper.innerHTML = ` <div class='bar'> <span>${val}</span> </div> `; } } 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++){ console.log("Constructing..."); const b = document.createElement('x-bar'); console.log("Setting attribute"); b.setAttribute('val', `value #${i}`); wrapper.appendChild(b); } shadow.appendChild(wrapper); } } customElements.define('x-foo', Foo);
<x-foo loop='3'></x-foo>
但是,从构造函数中调用方法并不理想,您可能需要摆弄一些
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.