自定义元素:monkeypatch 断开连接回调
Custom Elements: monkeypatch disconnected callback
我正在编写一个 Web 组件增强器函数,当元素从 DOM 中删除时我需要 运行 一些东西 - 但事后我知道这一点。
我使用了 MutationObserver - 但我的组件在页面周围使用了很多,并且多个突变观察器导致了性能问题。
这是在没有 MutationObserver 的情况下执行此操作的尝试:
class TestComponent extends HTMLElement {
disconnectedCallback() {
console.log('CB');
}
}
window.customElements.define('test-component', TestComponent);
function enrichComponent(component) {
const originalDisconnectedCallback = component.disconnectedCallback;
component.disconnectedCallback = function() {
originalDisconnectedCallback();
console.log('CB1');
}
}
const component = document.createElement('test-component');
enhancer(component);
document.body.appendChild(component);
component.remove(); // logs 'CB' but no 'CB1'
这行不通。
有没有办法'monkeypatch'disconnectedCallback
?
我已经想出了一个有效的“黑客”,而且比突变观察者成本更低。
想法是在增强器函数中创建一个组件,将其附加到 Web 组件,然后 运行 从模拟组件中清理函数。
这是一个例子:
class FormAssociationDisconnectionComponent extends HTMLElement {
disconnectedCallback() {
this.dispatchEvent(new Event('disconnected'));
}
}
window.customElements.define('form-association-disconnection', FormAssociationDisconnectionComponent);
function enrichComponent(component) {
// ... setup a form and a hidden input we need to cleanup
const removeListenerElement = document.createElement('form-association-disconnection');
removeListenerElement.addEventListener('disconnected', () => {
hiddenInput.remove();
hostingForm.removeEventListener('reset', resetFormHandler);
});
inputElement.appendChild(removeListenerElement);
}
这样,您可以 运行 在删除自定义元素时进行任何清理,而无需创建多个 MutationObservers。
我会把它分成两个解决方案,每个都更接近于特定的 use-case:
- 我(仍然,是的,我们讨论过)认为,如果是您自己的代码在该组件内创建
hiddenElement
- 最好在组件内进行整个管理,而不是 enrich/extend 它来自外部(是的,即使您对整个系统中的多个组件重复此模式)
- 如果绝对想从外部增强组件(比如不拥有 class,或者遇到多重继承问题)- 最好采用标准的事件驱动方法 -
disconnectedCallback
应该发送一个 disconnect
事件并且监听器应该附加到它 - 否则这个解决方案只是不可扩展/不开放扩展(想想另一个队友需要在断开连接时添加更多逻辑的情况,逻辑与第一个侦听器中的那个分离)
我正在编写一个 Web 组件增强器函数,当元素从 DOM 中删除时我需要 运行 一些东西 - 但事后我知道这一点。 我使用了 MutationObserver - 但我的组件在页面周围使用了很多,并且多个突变观察器导致了性能问题。
这是在没有 MutationObserver 的情况下执行此操作的尝试:
class TestComponent extends HTMLElement {
disconnectedCallback() {
console.log('CB');
}
}
window.customElements.define('test-component', TestComponent);
function enrichComponent(component) {
const originalDisconnectedCallback = component.disconnectedCallback;
component.disconnectedCallback = function() {
originalDisconnectedCallback();
console.log('CB1');
}
}
const component = document.createElement('test-component');
enhancer(component);
document.body.appendChild(component);
component.remove(); // logs 'CB' but no 'CB1'
这行不通。
有没有办法'monkeypatch'disconnectedCallback
?
我已经想出了一个有效的“黑客”,而且比突变观察者成本更低。
想法是在增强器函数中创建一个组件,将其附加到 Web 组件,然后 运行 从模拟组件中清理函数。
这是一个例子:
class FormAssociationDisconnectionComponent extends HTMLElement {
disconnectedCallback() {
this.dispatchEvent(new Event('disconnected'));
}
}
window.customElements.define('form-association-disconnection', FormAssociationDisconnectionComponent);
function enrichComponent(component) {
// ... setup a form and a hidden input we need to cleanup
const removeListenerElement = document.createElement('form-association-disconnection');
removeListenerElement.addEventListener('disconnected', () => {
hiddenInput.remove();
hostingForm.removeEventListener('reset', resetFormHandler);
});
inputElement.appendChild(removeListenerElement);
}
这样,您可以 运行 在删除自定义元素时进行任何清理,而无需创建多个 MutationObservers。
我会把它分成两个解决方案,每个都更接近于特定的 use-case:
- 我(仍然,是的,我们讨论过)认为,如果是您自己的代码在该组件内创建
hiddenElement
- 最好在组件内进行整个管理,而不是 enrich/extend 它来自外部(是的,即使您对整个系统中的多个组件重复此模式) - 如果绝对想从外部增强组件(比如不拥有 class,或者遇到多重继承问题)- 最好采用标准的事件驱动方法 -
disconnectedCallback
应该发送一个disconnect
事件并且监听器应该附加到它 - 否则这个解决方案只是不可扩展/不开放扩展(想想另一个队友需要在断开连接时添加更多逻辑的情况,逻辑与第一个侦听器中的那个分离)