[英]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.