自定义元素命名必须含短横线且全小写,避免与原生HTML元素冲突。构造函数仅执行super()和附加影子DOM,DOM操作必须移至connectedCallback中。样式需注入shadowRoot,外部CSS无效,以保障样式封装性。注册组件必须等待DOM完全就绪,否则组件静默失效无法使用。
如果直接使用mybutton或MyButton,浏览器会直接拒绝,并抛出DOMException: The name "xxx" is not a valid custom element name。只有像date-picker、status-badge、nav-menu这样带短横线且全小写的名称,才能通过注册。
这不是风格建议,而是硬性校验:调用customElements.define()的瞬间就会失败,组件根本进不了初始化流程。不要试图用try/catch兜底,错误发生在注册阶段,后续逻辑没有机会执行。
长期稳定更新的攒劲资源: >>>点此立即查看<<<
禁止使用下划线(my_button)、大写字母(UserCard)、单个单词(button),也不能与原生标签重名(例如div、slot、template)。此外,html-、svg-、math-这类保留前缀也要避开。
很多人在constructor里写this.innerHTML = ''或this.getAttribute('value'),结果发现属性读不到、样式不生效、this.shadowRoot是null。问题在于constructor执行时元素还没有挂载到文档,DOM上下文根本不可用。
正确的分工如下:
constructor只做三件事:调用super()、调用this.attachShadow({ mode: 'open' })(如果需要Shadow DOM)、初始化私有字段或绑定方法。this.shadowRoot.querySelector)、属性读取(this.getAttribute('label'))、事件监听(this.shadowRoot.addEventListener)、模板渲染,都必须放在connectedCallback里。attributeChangedCallback不会触发初始属性值,首次渲染还需要在connectedCallback里手动读取。disconnectedCallback要清理定时器和事件监听器,否则会导致内存泄漏。把写在自定义元素内部,或者用@import加载外部样式,在Shadow DOM里基本无效。Shadow DOM的样式隔离机制决定了:样式必须显式注入this.shadowRoot。
最稳妥的做法是在connectedCallback中拼接字符串并插入shadowRoot。例如:
const style = document.createElement('style');
style.textContent = `:host { display: inline-block; } .input { border: 1px solid #ccc; }`;
this.shadowRoot.appendChild(style);如果样式复杂,可以预编译为字符串常量,避免运行时重复解析。想让外部控制尺寸或主题色,要用CSS自定义属性配合:host选择器,例如:host([size="large"]) { font-size: 1.2em; }。
脚本放在里同步执行,而标签在里,浏览器解析到这个标签时customElements.define()还没有运行,就会当作普通未知元素处理——即使后面注册成功,也不会自动升级,connectedCallback永远不触发。
正确的做法有两种:
document.addEventListener('DOMContentLoaded', () => { customElements.define('my-card', MyCard); });包裹注册代码,确保在HTML解析完后执行。错误的做法是写成放在顶部。动态插入的即使加了defer,也不保证执行顺序。
插件式开发中,每个自定义元素都是独立可插拔的单元,但注册时机错一点,整个插件就会静默失效——它不会报错,只是不工作,排查起来特别隐蔽。
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述