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

浏览器扩展隔离内容脚本中自定义元素定义与使用问题求助

浏览器扩展隔离内容脚本中使用自定义元素的解决方案

原代码失败原因

隔离内容脚本运行在独立沙盒环境,其中的HTMLElement构造函数与主世界文档的HTMLElement并非同一引用。你定义的自定义元素继承自隔离环境的HTMLElement,但Shadow DOM属于主世界文档,实例化时浏览器会尝试用主世界的构造逻辑调用隔离环境的类,导致构造函数不兼容,最终抛出Illegal constructor错误。

可行解决方法

方法1:将自定义元素代码注入主世界执行

隔离脚本无法直接让自身环境的自定义元素在主世界DOM中生效,需把元素定义代码注入到主世界执行:

// 隔离内容脚本内的代码
// 定义自定义元素的逻辑(要注入到主世界)
const counterDef = `
class MyCounter extends HTMLElement {
  constructor() {
    super();
    const start = this.getAttribute('startvalue') || 0;
    const step = this.getAttribute('step') || 1;
    this.innerHTML = \`<button>Count: \${start}</button>\`;
    this.btn = this.querySelector('button');
    this.count = parseInt(start);
    this.btn.addEventListener('click', () => {
      this.count += parseInt(step);
      this.btn.textContent = \`Count: \${this.count}\`;
    });
  }
}
customElements.define('my-counter', MyCounter);
`;

// 创建脚本标签注入主世界
const script = document.createElement('script');
script.textContent = counterDef;
document.head.appendChild(script);
script.remove(); // 注入后清理脚本标签

// 现在可以在隔离脚本中创建元素并添加到页面
const container = document.createElement('div');
container.innerHTML = `<my-counter startvalue="1" step="3"></my-counter>`;
document.body.appendChild(container);

方法2:作用域化Registry配合主世界注入

如果不想全局注册自定义元素,可在注入主世界的代码中创建作用域化CustomElementRegistry,并绑定到指定Shadow DOM:

// 隔离内容脚本内的代码
const scopedSetup = `
class Counter extends HTMLElement {
  constructor() {
    super();
    // 自定义元素逻辑
    const start = this.getAttribute('startvalue') || 0;
    const step = this.getAttribute('step') || 1;
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = \`<span>Count: \${start}</span><button>+</button>\`;
    this.count = parseInt(start);
    this.shadowRoot.querySelector('button').addEventListener('click', () => {
      this.count += parseInt(step);
      this.shadowRoot.querySelector('span').textContent = \`Count: \${this.count}\`;
    });
  }
}

const scopedRegistry = new CustomElementRegistry();
scopedRegistry.define('my-counter', Counter);

// 暴露方法给隔离脚本调用(用完即删避免污染)
window.__createScopedCounter = () => {
  const container = document.createElement('div');
  container.attachShadow({
    mode: 'open',
    customElementRegistry: scopedRegistry
  });
  container.shadowRoot.innerHTML = '<my-counter startvalue="1" step="3"></my-counter>';
  return container;
};
`;

// 注入主世界
const script = document.createElement('script');
script.textContent = scopedSetup;
document.head.appendChild(script);
script.remove();

// 调用主世界方法获取容器并添加
const container = window.__createScopedCounter();
document.body.appendChild(container);
delete window.__createScopedCounter;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.05 05:12:31