You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在自定义Web Components中重写/代理disconnectedCallback

问题:无法代理自定义元素实例的disconnectedCallback

尝试代理自定义元素实例的disconnectedCallback,但浏览器触发回调时代理逻辑未执行,仅原方法生效。简化测试代码如下:

const template = document.createElement("template");
template.innerHTML = `<button id="button">Click ME</button>`;

customElements.define("custom-test", class extends HTMLElement {
    constructor() {
      super();
      this.attachShadow({ mode: "open" });
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

    disconnectedCallback() {
      console.log("Disconnected Callback")
    }
  },
);

let test = document.createElement('custom-test')
test = (function () {
  const fn = test.disconnectedCallback;
  test.disconnectedCallback = function () {
    console.log("proxy function")
    fn.apply(test)
  }
  return test;
})()

document.body.appendChild(test)

const div = document.createElement('div');
div.appendChild(test);
// 实际仅输出 "Disconnected Callback"

预期输出:

proxy function
Disconnected Callback

实际输出:仅第二行内容,代理函数未触发。手动调用test.disconnectedCallback()时代理逻辑正常执行,但使用new Proxy生成的代理对象无法用于appendChild方法。


解决方案

原因分析

自定义元素的生命周期回调(如disconnectedCallback)是浏览器直接从原型链调用的,不会读取实例自身的同名属性。直接给实例赋值disconnectedCallback,浏览器触发回调时会跳过这个实例属性,直接调用原型上的原方法。

两种可行实现方式

方式1:仅修改目标实例的原型链(推荐,不影响其他实例)

给目标实例单独设置一个继承自原自定义元素原型的新原型,在新原型中重写disconnectedCallback:

let test = document.createElement('custom-test')

// 创建继承自原原型的新原型对象
const instanceProto = Object.create(test.constructor.prototype);
// 重写回调方法,加入代理逻辑
instanceProto.disconnectedCallback = function() {
  console.log("proxy function");
  // 调用原原型的回调方法
  test.constructor.prototype.disconnectedCallback.apply(this, arguments);
};
// 为当前实例设置新原型
Reflect.setPrototypeOf(test, instanceProto);

// 后续代码不变
document.body.appendChild(test)
const div = document.createElement('div');
div.appendChild(test);
// 输出符合预期:proxy function → Disconnected Callback

方式2:修改类原型的回调方法(影响同类型所有实例)

如果不需要区分实例,可直接修改自定义元素类原型上的disconnectedCallback:

let test = document.createElement('custom-test')
const originalCallback = test.constructor.prototype.disconnectedCallback;

// 重写原型上的回调方法
test.constructor.prototype.disconnectedCallback = function() {
  console.log("proxy function");
  originalCallback.apply(this, arguments);
};

// 后续代码不变
document.body.appendChild(test)
const div = document.createElement('div');
div.appendChild(test);

验证说明

修改后,当元素从DOM中移除时,浏览器会调用新原型/修改后的原型方法,触发代理逻辑,再执行原回调内容,符合预期输出。


内容的提问来源于stack exchange,提问作者mattematt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 09:25:25