簡體   English   中英

attributeChangedCallback() 總是被調用兩次以多個事件監聽器結束

[英]attributeChangedCallback() always called twice ending up with multiple event listeners

玩弄自定義元素,我試圖根據自定義元素屬性的值觸發點擊事件。 但是使用attributeChangedCallback()方法(以及connectedCallback()方法)我最終得到了多個事件偵聽器。

 class HelloWorld extends HTMLElement { static get observedAttributes() { return ['attribute1', 'attribute2']; } get attribute1() { return this.getAttribute('attribute1'); } set attribute1(val) { if (val) { this.setAttribute('attribute1', val); } else { this.removeAttribute('attribute1'); } } get attribute2() { return this.getAttribute('attribute2'); } set attribute2(val) { if (val) { this.setAttribute('attribute2', val); } else { this.removeAttribute('attribute2'); } } constructor() { super(); } connectedCallback() { this.textContent = 'Hello World'; update(this); } attributeChangedCallback(name, oldValue, newValue) { update(this); } } customElements.define('hello-world', HelloWorld); function update(el) { if (el.attribute1 === 'foo') { el.addEventListener('click', e => { el.textContent = (el.textContent.indexOf(' (') != -1 ? el.textContent.substring(0, el.textContent.indexOf(' (')) : el.textContent) + ' (clicked ' + (el.textContent.match(/\d+/) ? parseInt(el.textContent.match(/-?\d+/)[0]) + 1 : 1) + ' times)'; }); } else if (el.attribute1 === 'bar') { el.addEventListener('click', e => { el.textContent = (el.textContent.indexOf(' (') != -1 ? el.textContent.substring(0, el.textContent.indexOf(' (')) : el.textContent) + ' (clicked ' + (el.textContent.match(/\d+/) ? parseInt(el.textContent.match(/-?\d+/)[0]) - 1 : 1) + ' times)'; }); } }
 hello-world { cursor: pointer; }
 <hello-world attribute1="foo" attribute2=""></hello-world>

為什么attributeChangedCallback()方法總是被調用兩次並因此添加了兩個事件監聽器? 如何避免這種情況? 什么是最佳實踐?

它被稱為attributeChangedCallback ,因此會在每個屬性更改時觸發,包括將元素添加到 DOM 時的 init

connectedCallback中附加偵聽器,但是如果您在 DOM 中移動元素,它可以再次運行,因此您必須在disconnectedCallback中刪除它們

使用內聯EventHandler 可能更簡單,元素上只能有一個。

 customElements.define('hello-world', class extends HTMLElement { static get observedAttributes() { return ['attribute1', 'attribute2']; } get attribute1() { return this.getAttribute('attribute1'); } set attribute1(val) { this.toggleAttribute('attribute1', val); } get attribute2() { return this.getAttribute('attribute2'); } set attribute2(val) { this.toggleAttribute('attribute2', val); } connectedCallback() { this.count = 0; this.innerHTML = `Hello World clicked: <span>${this.count}</span> times`; this.onclick = (evt) => { this.count++; this.querySelector("span").innerHTML = this.count; } } attributeChangedCallback(name, oldValue, newValue) { console.log("attributeChangedCallback", name, oldValue, newValue); } });
 hello-world { cursor: pointer; }
 <hello-world attribute1="foo" attribute2=""></hello-world>

constructor() {
  super()
}

不是必需的,不存在的constructor函數將從其父級執行constructor 。這是super()所做的。

如果要阻止多個偵聽器,可以嘗試一種方法:

addListeners(){
  .. add your listeners

  this.addListeners = () => {}; // overload; Don't run its original code again
}

另請注意,當從 DOM 中刪除元素時,您在元素(或其內容)上添加的偵聽器會自動收集/刪除所有垃圾。
您在其他 DOM 元素(例如文檔)上添加的任何偵聽器都必須在disconnectedCallback中刪除

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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