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[=22= 时的初始化]
在 connectedCallback
中附加侦听器,但是如果您在 DOM 中移动元素,那么 可以 运行 再次在 disconnectedCallback
中删除它们
使用 内联 事件处理程序可能更简单,一个元素上只能有一个。
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
中自行删除
尝试使用自定义元素,我试图根据自定义元素属性的值触发点击事件。但是使用 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[=22= 时的初始化]
在 connectedCallback
中附加侦听器,但是如果您在 DOM 中移动元素,那么 可以 运行 再次在 disconnectedCallback
使用 内联 事件处理程序可能更简单,一个元素上只能有一个。
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