customElements.define不支持传参,配置须通过observedAttributes声明的HTML属性注入;首次初始化在connectedCallback中读取attribute并fallback默认值,attributeChangedCallback响应后续变更,property与attribute需手动同步且注意类型转换。

customElements.define 时如何传入默认配置
自定义元素本身不支持直接在 customElements.define 阶段传参,所有配置必须通过属性(attribute)或属性映射(observedAttributes)注入。浏览器只会在元素被插入 DOM 后触发 attributeChangedCallback,因此「预设值」不能靠构造函数参数硬编码,而要依赖 attribute 初始化逻辑。
- 必须将配置项设计为可反射的 HTML 属性,例如
data-theme、max-items、disabled - 在
static get observedAttributes()中声明这些属性,否则attributeChangedCallback不会触发 - 首次初始化时,
connectedCallback可读取当前 attribute 值,但若属性尚未设置,需 fallback 到内部默认值(如this._theme = this.getAttribute('data-theme') || 'light') - 避免在
constructor中访问this.getAttribute—— 此时 DOM 尚未挂载,attribute 可能为空字符串而非null,且无法区分「未设置」和「显式设为空」
如何让 attribute 和 property 保持同步
用户常误以为设置 el.maxItems = 5 会自动更新 el.getAttribute('max-items'),但原生行为不会同步。若需双向绑定,必须手动桥接:
- 定义 setter:当 JS 修改 property 时,显式调用
this.setAttribute('max-items', value) - 在
attributeChangedCallback中更新对应 property,并触发重渲染(如调用this.render()) - 注意类型转换:HTML attribute 总是字符串,
max-items="5"读出来是"5",需parseInt或JSON.parse处理 - 布尔属性(如
disabled)更易出错:disabled="false"仍会被视为 true;正确做法是用hasAttribute('disabled')判断,而非getAttribute('disabled') === 'true'
data-* 属性 vs 自定义属性:该用哪个存配置
data-* 是合法全局属性,适合存非控件逻辑的元数据(如 data-user-id="123");而组件行为配置应使用语义化自定义属性(如 items-per-page),原因如下:
-
data-*不会触发observedAttributes,除非你显式写进列表,增加维护成本 - 自定义属性名更贴近组件意图,便于文档与 IDE 自动补全(如 VS Code 能识别
show-header) -
datasetAPI 会把连字符转成驼峰(data-api-key→el.dataset.apiKey),但对组件核心行为属性而言,这种隐式转换反而增加理解负担 - 若配置需参与样式计算(如
[size="large"] { font-size: 1.2em; }),必须用普通 attribute,data-*不支持 CSS 选择器匹配
预设值管理容易被忽略的边界点
真正难的不是写默认值,而是判断「谁有权限覆盖它」。比如一个 <date-picker> 组件,其 min-date 应由业务层控制,但组件内部的 locale 默认值可能来自浏览器 navigator.language —— 这类动态默认值必须在 connectedCallback 中延迟获取,不能写死在 class 字段里。
立即学习“前端免费学习笔记(深入)”;
- 静态默认值(如
static defaultConfig = { size: 'medium' })适合纯 UI 参数 - 动态默认值(如基于
window.matchMedia或localStorage)必须在生命周期回调中计算,否则 SSR 或测试环境会出错 - 禁止在
attributeChangedCallback中修改其他 attribute —— 可能引发无限循环(A 改 B → B 触发回调 → B 改 A) - 如果组件支持主题切换,预设值应随主题上下文变化,此时需监听
document.documentElement的 class 变更,而非仅依赖初始 attribute



















