自定义元素命名须含短横线且全小写,constructor中仅初始化、不可操作dom,表单参与需显式启用formassociated并调用attachinternals(),shadow dom推荐用于样式隔离,attributechangedcallback不响应初始属性值。

自定义元素命名必须含短横线且全小写
浏览器会直接拒绝注册不合规的名称,比如 mybutton、MyButton、my_button 或 div —— 这些都会在调用 customElements.define() 时抛出 DOMException。
合法名称必须同时满足三点:含至少一个 ASCII 短横线(-)、全部小写字母、不与任何原生标签重名。常见错误是试图用单个单词或驼峰式命名,结果连注册这一步都卡住。
-
user-profile✅ -
date-picker✅ -
status-badge✅ -
myinput❌(缺短横线) -
MyInput❌(含大写) -
input-field❌(与原生input语义冲突,虽不报错但行为不可控)
constructor 只能做初始化,不能操作 DOM
很多初学者在 constructor 里直接读取 this.getAttribute()、修改 this.innerHTML 或调用 this.querySelector(),结果要么返回 null,要么触发“无法在未挂载元素上执行 DOM 查询”的错误。
原因很简单:此时元素还没插入文档,connectedCallback 才是首次可安全访问子节点、绑定事件、读取属性的地方。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- ✅
super()必须第一行调用 - ✅ 创建 Shadow DOM:
this.attachShadow({mode: 'open'}) - ✅ 初始化私有字段:
this._value = '' - ❌ 修改
this.innerHTML - ❌ 调用
this.querySelector() - ❌ 注册事件监听器(除非监听自身生命周期事件)
表单参与必须显式启用 formAssociated
写了 <my-input></my-input> 却发现提交时值没进 form.data?大概率是因为漏了 formAssociated: true 选项,或者没调用 this.attachInternals()。
自治型自定义元素(autonomous custom elements)默认不参与表单逻辑,必须主动接入。否则它只是个“长得像输入框的 div”,和 <div></div> 在表单中地位完全一样。
- 构造函数中必须调用
this.internals = this.attachInternals() -
customElements.define('my-input', MyInput, { formAssociated: true })缺一不可 - 在
connectedCallback中监听子<input>的input事件,并调用this.internals.setFormValue(value) - 不要尝试继承
HTMLInputElement—— Chrome v100+ 已限制,Firefox/Safari 基本不支持
Shadow DOM 不是必须项,但样式隔离强烈推荐
你可以不用 attachShadow,直接操作 this.innerHTML,但这样就失去了封装性:外部 CSS 会穿透进来,你的组件样式可能被全局规则意外覆盖,反之亦然。
真正需要 Shadow DOM 的场景,不是“想用新技术”,而是“这个组件要嵌入未知样式的页面”——比如 CMS 插件、第三方工具栏、SaaS 平台的嵌入式控件。
- ✅
this.attachShadow({mode: 'open'})允许 JS 外部访问 shadowRoot,调试友好 - ✅ 在
shadowRoot.innerHTML中内联样式,或动态注入<style></style> - ❌ 把样式写在全局 CSS 文件里再指望它只作用于组件内部
- ❌ 用
mode: 'closed'—— 它切断了所有外部访问路径,包括自动化测试和 DevTools 检查
attributeChangedCallback 不会响应初始属性值 —— 比如 <user-profile name="Alice"></user-profile> 中的 name,第一次渲染仍得靠 connectedCallback 读取,否则组件启动就缺数据。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










