自定义元素名必须含短横线,constructor中须调用super()并attachShadow({mode:'open'}),attributeChangedCallback需配合slot实现双向同步,CSS隔离需用:host-context或::part,生命周期逻辑须防重复执行。

自定义元素名必须带短横线,否则 customElements.define() 直接报错
浏览器强制要求自定义标签名含至少一个短横线(-),比如 html-editor 合法,htmleditor、HtmlEditor、editor 全部失败,错误信息是:Failed to execute 'define' on 'CustomElementRegistry': The name "htmleditor" is not a valid custom element name。这不是规范建议,而是硬性语法校验——为防未来 HTML 标准新增原生标签时冲突。命名一旦定下,后续所有引用(HTML 使用、CSS 选择器、JS 查询)都得保持一致,改名等于重写整个调用链。
constructor 里必须调用 super() 并挂载 Shadow DOM
不挂 Shadow DOM 就谈不上封装:外部样式会穿透进来,内部样式也可能污染全局。必须在 constructor 中调用 this.attachShadow({ mode: 'open' }),mode: 'open' 是调试刚需,它让 this.shadowRoot 可被 DevTools 直接展开查看;若用 'closed',连 JS 都拿不到 shadowRoot 引用,基本等于自废调试能力。注意:不能在 connectedCallback 里挂载,否则每次元素被移除再插入都会重复 attach,触发 DOM 异常。
常见错误包括:
- 在
connectedCallback中写this.innerHTML = '...'—— 这样完全没隔离,样式和结构全暴露 - 漏掉
super(),导致继承链断裂,this.getAttribute()等方法不可用 - 把模板字符串直接赋给
shadowRoot.innerHTML,但其中含内联事件(如onclick="...")—— Shadow DOM 中内联事件无效,必须用this.shadowRoot.addEventListener()
编辑器内容同步靠 attributeChangedCallback + slot 双路控制
纯属性传值(如 <html-editor content="<p>Hello</p><p><span>立即学习</span>“<a href=" https: style="text-decoration: underline !important; color: blue; font-weight: bolder;" rel="nofollow" target="_blank">前端免费学习笔记(深入)”;</html-editor>
<slot></slot> 接收初始 HTML 片段,并在内部 contenteditable 区域变更时,用 dispatchEvent(new CustomEvent('change', { detail: this.innerHTML })) 主动通知外部。关键点:
-
static get observedAttributes()必须显式声明要监听的属性,比如['content', 'placeholder'],没列进去的属性变更是不会触发attributeChangedCallback的 - 不要在
attributeChangedCallback里直接操作this.innerHTML,而应更新this.shadowRoot.querySelector('[contenteditable]').innerHTML - 如果允许用户粘贴富文本,记得监听
input和paste事件,而不是只靠change——contenteditable元素的change事件不触发
CSS 隔离与外部样式穿透的取舍很实际
Shadow DOM 默认阻止外部 CSS 影响内部,这是好事,但编辑器常需支持主题色、字体等定制。别指望 !important 能穿透,真正可用的方式只有两种:
- 用
:host-context(.dark-theme) .editor { background: #1e1e1e; }响应外部容器 class - 暴露
part属性,比如<div part="toolbar">,然后外部用 <code>html-editor::part(toolbar)选中并样式化(注意:IE 不支持,Chrome 87+ 才稳定)另外,
contenteditable元素的光标颜色、选区样式无法用普通 CSS 控制,得用::selection和::-webkit-scrollbar等伪类,且它们在 Shadow DOM 内必须写在组件自己的<style>块里,外部无法覆盖。最易被忽略的是生命周期误用:很多人把初始化逻辑全塞进
connectedCallback,但该钩子可能被反复调用(比如元素被appendChild→removeChild→ 再appendChild)。编辑器这类有状态组件,必须在constructor或首次connectedCallback中加标记(如this._initialized = true),避免重复绑定事件或重复创建 iframe/编辑器实例。



















