html自定义组件api设计核心是语义化与约定优于配置:只暴露value、disabled等语义属性,状态通过事件/方法通知;attributechangedcallback中延迟更新并浅比较;对外方法统一返回promise;扩展靠slot和事件而非配置项。

HTML 自定义组件的 API 设计,核心不是“能暴露多少”,而是“开发者不看文档就能猜对怎么用”。value、disabled、required 这类语义化属性必须直接支持,而不是逼人调 setValue() 或查 isDisabled 状态。
只暴露语义化属性,别暴露内部状态
常见错误是把组件内部变量全挂成属性:比如 isFocused、hasError、isLoading。这会让使用者陷入手动同步泥潭——你改了 value,还得手动设 hasError = false,逻辑耦合且易错。
正确做法是只保留对外有明确业务含义的属性:
-
value(字符串/数字,受控值) -
min/max(数值约束) -
disabled(布尔属性,用this.hasAttribute('disabled')判断,不是this.disabled === true) -
placeholder(仅当输入类组件需要时)
其余状态一律通过事件通知:change、input、focus、blur、error;或方法控制:focus()、reset()、validate()。
attributeChangedCallback 里别直接更新 DOM
这个回调不是“属性一变就立刻重绘”的快捷通道。浏览器可能批量触发它(例如 SSR 注入多个属性),直接操作 DOM 会卡顿,还容易和初始化逻辑打架。
稳妥做法是延迟合并执行:
- 用
Promise.resolve().then(() => { /* 更新逻辑 */ })推迟到微任务末尾,自动合并多次变更 - 对字符串类属性(如
format)做浅比较:if (oldValue === newValue) return - 绝对避免在回调里调
this.setAttribute(),否则会再次触发自身,形成死循环(尤其带默认值处理时)
对外方法统一返回 Promise
哪怕当前实现是同步的,所有公开方法也应返回 Promise。原因很实在:今天没异步,明天加个 i18n 加载、图标懒加载、或 Web Worker 校验,同步方法就得推倒重来。
示例:
async validate() {
if (this._pendingValidation) return this._pendingValidation;
this._pendingValidation = this._doValidate();
try {
await this._pendingValidation;
} finally {
this._pendingValidation = null;
}
return this._pendingValidation;
}
调用方始终可写 await el.validate(),不用关心底层是否已异步化。错误统一 reject(new Error(...)),不混用 console.error + return false。
slot 和 event 才是真正的扩展点
别试图用一堆配置项覆盖所有 UI 变体。真正可扩展的组件靠的是结构开放:
- 用
<slot name="label"></slot>让使用者自定义标签内容,而不是提供labelText属性 - 用
<slot name="icon"></slot>插入任意图标,而不是内置 SVG +iconName枚举 - 关键行为发事件:
custom-change比onchange更可控,避免被原生事件机制劫持
复杂交互场景下,组合 slot + event + method(如 open())比堆砌 20 个属性更轻量、更可维护。最容易被忽略的一点:slot fallback 内容必须有意义,不能只是空 <span></span> —— 它是降级时的最后防线。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











