自定义元素: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 事件并且监听器应该附加到它 - 否则这个解决方案只是不可扩展/不开放扩展(想想另一个队友需要在断开连接时添加更多逻辑的情况,逻辑与第一个侦听器中的那个分离)