0

0

javascript的custom elements如何定义_如何创建和使用自己的html元素【教程】

夢幻星辰

夢幻星辰

发布时间:2026-01-16 20:34:03

|

703人浏览过

|

来源于php中文网

原创

custom elements 是 web components 的核心,需继承 htmlelement、含短横线命名,用 customelements.define() 注册;构造函数必须调用 super() 初始化 this,attributechangedcallback 仅响应 observedattributes 中声明的属性变更,且受浏览器兼容性与 dom 结构限制。

javascript的custom elements如何定义_如何创建和使用自己的html元素【教程】

Custom Elements 是 Web Components 的核心之一,它允许你定义自己的 HTML 标签,但不是靠封装或模拟,而是真正注册进浏览器的 DOM 系统——这意味着 document.createElement('my-button') 能返回合法元素,instanceof 会通过校验,且能被 querySelector、框架的 ref、甚至原生表单逻辑识别。

如何用 customElements.define() 注册一个自定义元素

必须继承 HTMLElement(或其子类如 HTMLButtonElement),且类名中必须含短横线(-),这是强制语法限制,否则抛出 DOMException: The element name must contain a hyphen

  • 类不能是匿名函数或箭头函数,必须有命名(哪怕只是 class MyCard extends HTMLElement
  • 注册前必须先声明类,顺序不能颠倒;若重复注册同一名称,会报错 Failed to execute 'define' on 'CustomElementRegistry': the name "x-foo" has already been used
  • 名称不能以 x- 开头再加短横线(如 x-foo-bar 合法,x--foo 不合法),也不能是保留名(如 htmlslottemplate
class MyCounter extends HTMLElement {
  constructor() {
    super();
    this.count = 0;
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `
      <style>button { font-size: 14px; }</style>
      <button><slot></slot>: ${this.count}</button>
    `;
  }

  connectedCallback() {
    this.shadowRoot.querySelector('button').addEventListener('click', () => {
      this.count++;
      this.shadowRoot.querySelector('button').textContent = `${this.textContent}: ${this.count}`;
    });
  }
}

customElements.define('my-counter', MyCounter);

为什么必须用 constructor + super()

因为 Custom Element 构造函数在 DOM 初始化阶段被调用(比如解析 HTML 字符串时),此时元素尚未插入文档,也无父节点。不调用 super() 会导致 this 未初始化,后续所有操作(如 attachShadowsetAttribute)都会失败,并静默报错或直接崩溃。

  • connectedCallbackdisconnectedCallback 可以安全访问 this.parentNode,但 constructor 里永远不能
  • attributeChangedCallback 的触发前提是:该属性在 observedAttributes 中声明,且元素已定义完成——也就是说,它不会在 constructor 执行期间触发
  • 不要在 constructor 里调用 this.innerHTML 或读取 this.children,它们为空;应改用 slotinnerHTML 写入 shadow DOM

如何让自定义元素支持 HTML 属性并响应变更

仅靠 setAttribute 不会自动触发更新,必须显式监听属性变化。浏览器只会在属性值字符串发生变化时调用 attributeChangedCallback,且仅限于 observedAttributes 返回的数组中列出的属性名。

通义灵码
通义灵码

阿里云出品的一款基于通义大模型的智能编码辅助工具,提供代码智能生成、研发智能问答能力

下载

立即学习Java免费学习笔记(深入)”;

  • 属性名自动转为小写(My-Propmy-prop),所以 observedAttributes 必须写小写形式
  • 若属性初始值来自 HTML(如 <my-input value="hello"></my-input>),attributeChangedCallback 会在 connectedCallback 前触发一次
  • 注意:布尔属性(如 disabled)的变更,newValue""(空字符串)而非 true;需用 this.hasAttribute('disabled') 判断
class MyInput extends HTMLElement {
  static get observedAttributes() {
    return ['value', 'disabled'];
  }

  attributeChangedCallback(name, oldValue, newValue) {
    switch (name) {
      case 'value':
        this.input.value = newValue || '';
        break;
      case 'disabled':
        this.input.disabled = this.hasAttribute('disabled');
        break;
    }
  }

  constructor() {
    super();
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `<input type="text" class="input">`;
    this.input = this.shadowRoot.querySelector('input');
  }
}

customElements.define('my-input', MyInput);

使用时要注意哪些兼容性与陷阱

Chrome / Edge / Safari 原生支持良好,Firefox 从 63+ 支持,但 IE 完全不支持(无 polyfill 可完美还原行为)。即便现代浏览器,也有几个容易忽略的点:

  • 自定义元素无法直接作为 <table> 的子元素(如 <code><my-row></my-row> 放在 <tbody> 里)——浏览器会把它“提升”到 table 外,破坏结构;必须用 <code>is 语法:<tr is="my-row"> <li>服务端渲染(SSR)时,若 JS 未加载,自定义元素会表现为未知标签,样式和交互全部失效;建议配合 <code>customElements.whenDefined() 做降级处理
  • 若元素内使用了 slot,且宿主元素有 innerHTML 设置,内容不会自动投射——必须等 connectedCallback 触发后才生效
  • 最常被跳过的一步:没检查是否已定义就重复 define,尤其在模块热更新或微前端场景下。上线前务必加一层守卫:

    if (!customElements.get('my-card')) {
      customElements.define('my-card', MyCard);
    }

    真正的难点不在语法,而在生命周期节奏——什么时候能读 DOM、什么时候能改样式、什么时候能发事件,全都取决于你对 constructor / connectedCallback / attributeChangedCallback 三者触发时机和约束条件的理解是否精确。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
chrome什么意思
chrome什么意思

chrome是浏览器的意思,由Google开发的网络浏览器,它在2008年首次发布,并迅速成为全球最受欢迎的浏览器之一。本专题为大家提供chrome相关的文章、下载、课程内容,供大家免费下载体验。

1028

2023.08.11

chrome无法加载插件怎么办
chrome无法加载插件怎么办

chrome无法加载插件可以通过检查插件是否已正确安装、禁用和启用插件、清除插件缓存、更新浏览器和插件、检查网络连接和尝试在隐身模式下加载插件方法解决。更多关于chrome相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

823

2023.11.06

edge是什么浏览器
edge是什么浏览器

Edge是一款由Microsoft开发的网页浏览器,是Windows 10操作系统中默认的浏览器,其目标是提供更快、更安全、更现代化的浏览器体验。本专题为大家提供edge浏览器相关的文章、下载、课程内容,供大家免费下载体验。

1697

2023.08.21

IE浏览器自动跳转EDGE如何恢复
IE浏览器自动跳转EDGE如何恢复

ie浏览器自动跳转edge的解决办法:1、更改默认浏览器设置;2、阻止edge浏览器的自动跳转;3、更改超链接的默认打开方式;4、禁用“快速网页查看器”;5、卸载edge浏览器;6、检查第三方插件或应用程序等等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

395

2024.03.05

如何解决Edge打开但没有标题的问题
如何解决Edge打开但没有标题的问题

若 Microsoft Edge 浏览器打开后无标题(窗口空白或标题栏缺失),可尝试以下方法解决: 重启 Edge:关闭所有窗口,重新启动浏览器。 重置窗口布局:右击任务栏 Edge 图标 → 选择「最大化」或「还原」。 禁用扩展:进入 edge://extensions 临时关闭插件测试。 重置浏览器设置:前往 edge://settings/reset 恢复默认配置。 更新或重装 Edge:检查最新版本,或通过控制面板修复

1025

2025.04.24

typedef和define区别
typedef和define区别

typedef和define区别在类型检查、作用范围、可读性、错误处理和内存占用等。本专题为大家提供typedef和define相关的文章、下载、课程内容,供大家免费下载体验。

119

2023.09.26

define的用法
define的用法

define用法:1、定义常量;2、定义函数宏:3、定义条件编译;4、定义多行宏。更多关于define的用法的内容,大家可以阅读本专题下的文章。

361

2023.10.11

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

718

2023.08.03

Rust内存安全机制与所有权模型深度实践
Rust内存安全机制与所有权模型深度实践

本专题围绕 Rust 语言核心特性展开,深入讲解所有权机制、借用规则、生命周期管理以及智能指针等关键概念。通过系统级开发案例,分析内存安全保障原理与零成本抽象优势,并结合并发场景讲解 Send 与 Sync 特性实现机制。帮助开发者真正理解 Rust 的设计哲学,掌握在高性能与安全性并重场景中的工程实践能力。

19

2026.03.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 5.8万人学习

TypeScript 教程
TypeScript 教程

共19课时 | 3.3万人学习

Bootstrap 5教程
Bootstrap 5教程

共46课时 | 3.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号