簡體   English   中英

自定義元素未設置/獲取屬性

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

摘要是:

您的構造函數代碼:

  • 作為構造函數中的第一條語句,必須對super()進行無參數調用。
  • 構造函數中的任何地方都不能有return語句。
  • 不得調用document.write()或document.open()。
  • 不得檢查元素的屬性。
  • 不得更改或添加任何屬性或子級。

通常,應使用構造函數來設置初始狀態和默認值,並設置事件偵聽器以及可能的影子根。

總的來說,我同意@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); 

這使用了attributeChangedCallbackobservedAttributes的標准。 盡管覆蓋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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM