使自定义元素通过作用域注册表运行

Jayson Chen
Jayson Chen
Patrick Brosset
Patrick Brosset

发布时间:2026 年 3 月 9 日

借助自定义元素,Web 应用开发者可以构建、分享和重复使用具有独特行为的界面组件,从而简化开发流程。但如果您的应用将不同的自定义元素集组合在一起,情况可能会变得混乱,并可能发生名称冲突。 作用域限定的自定义元素注册表可解决此问题!

Microsoft Edge 团队一直在努力开发此功能,我们很高兴地宣布,从 Edge 和 Chrome 146 以及其他基于 Chromium 的浏览器开始,范围限定的自定义元素注册表现在默认可用。现在,您可以封装自定义元素,从而解决组件和微前端库开发者长期以来面临的痛点。

Browser Support

  • Chrome: 146.
  • Edge: 146.
  • Firefox: not supported.
  • Safari: 26.

Source

作用域限定的自定义元素注册表为 Web 开发者提供了重要的模式。 现在,您可以并排使用由多个团队独立开发的多个自定义元素库,或同一库的多个版本。

样式截然不同的两个按钮。

什么是作用域自定义元素注册表?

如今,网页上的每个自定义元素定义都位于 window.customElements 中的单个共享注册表中。这意味着,如果两个不同的库都尝试定义具有相同标记名称(例如 <my-button>)的自定义元素,系统会抛出错误,并且网页会中断。这在现实世界中是一个严重的问题。如果大型应用的用户界面由多个团队、设计系统或微前端组成,则很容易遇到命名冲突。范围限定的自定义元素注册表通过允许您创建独立注册表来解决此问题。每个注册表都维护着自己的一组自定义元素定义,这些定义与全局注册表和其他注册表完全隔离。

创建新注册表

无需在全局 window.customElements 注册表中定义每个自定义元素,而是:

  1. 通过调用 new CustomElementRegistry() 创建新注册表。
  2. 为新注册表指定特定范围(请参阅“确定注册表的范围”)。
  3. 定义新注册数据库中包含的元素。

然后,当使用自定义元素时,浏览器会从关联的注册表中查找该元素的定义,该注册表不一定是全局注册表。这意味着,网页的不同部分可以使用完全不同的自定义元素定义集。

确定注册表的范围

自定义元素注册表可以限定为文档、影子根或单个元素。

将范围限定为影子根

如需将新注册表限定到影子根,请在调用 attachShadow() 方法时使用 customElementRegistry 选项。现在,位于该影子根中的所有自定义元素都将使用相应作用域注册表中的定义:

// Create your custom registry.
const registry = new CustomElementRegistry();
// Define a custom element in the new registry.
registry.define('my-card', class extends HTMLElement {
  connectedCallback() {
    this.textContent = 'Hello from scoped registry!';
  }
});

// Create shadow root, providing it with your new custom element registry.
const host = document.querySelector('#host');
const shadow = host.attachShadow({
  mode: 'open',
  customElementRegistry: registry,
});

shadow.innerHTML = '<my-card></my-card>';

声明式 shadow DOM

<template> 元素上使用 shadowrootcustomelementregistry 属性,告知浏览器生成的影子根使用的是作用域注册表,而不是全局注册表:

<my-host>
  <template shadowrootmode="open" shadowrootcustomelementregistry>
    <my-widget></my-widget>
  </template>
</my-host>
  const registry = new CustomElementRegistry();
  registry.define('my-widget', class extends HTMLElement {
    connectedCallback() { this.textContent = 'Scoped!'; }
  });

  const shadow = document.querySelector('my-host').shadowRoot;
  registry.initialize(shadow);

如示例所示,该属性会为自定义元素注册表预留空间,用户需要定义注册表并将其初始化为断开连接的文档的影子根作用域

您还可以将注册表限定为某个文档,例如由 document.implementation.createHTMLDocument() 创建的文档。这样一来,您就可以克隆 <template> 元素,并进行屏幕外文档操作,每个操作都有自己的一组隔离的组件定义。为此,请使用 CustomElementRegistry.initialize() 方法:

// Create a new registry.
const registry = new CustomElementRegistry();
registry.define('app-widget', AppWidget);

// Create a document, and use registry.initialize() to scope the registry to the document.
const doc = document.implementation.createHTMLDocument('');
registry.initialize(doc);

doc.body.innerHTML = '<app-widget></app-widget>';

将范围限定为单个元素

您还可以通过将 customElementRegistry 选项传递给 document.createElement(),直接将注册表与元素及其子树相关联。无论该元素及其后代元素稍后插入到 DOM 的哪个部分,它们都会针对该注册表进行解析:

// Create a registry and define a custom element in it.
const registry = new CustomElementRegistry();
registry.define('fancy-label', FancyLabel);

// Create a new DOM element and scope the new registry to it.
const el = document.createElement('fancy-input', {
  customElementRegistry: registry,
});

// Use a custom element in the new DOM element.
el.innerHTML = '<fancy-label>Name</fancy-label>';

了解详情

如需了解详情,请查看 Edge 演示及其源代码,并阅读 MDN 的 CustomElementRegistry 参考文章

通过 Chromium 项目的协作,我们现在已在 Microsoft Edge 和 Chrome 以及其他基于 Chromium 的浏览器中默认启用范围限定的自定义元素注册表。

您无需启用任何设置或注册源试用。您今天就可以在基于 Chromium 的浏览器中使用此功能。

如果您需要在其他浏览器中实现此功能,请对“Scoped custom element registries”问题表示赞同,并发表评论,说明您的使用情形和解决方法。

如果您在基于 Chromium 的浏览器中发现该功能存在 bug,请前往 crbug.com/new 为我们提交问题,以便我们进行调查。

我们希望作用域限定的自定义元素注册表能让您更轻松地使用 Web 组件。