如何在TypeScript中实现DOM元素扩展类 支持原生与自定义方法直接调用
TypeScript DOM元素扩展类实现方案
要实现自定义方法和原生DOM方法统一调用,需要同时处理类型声明和运行时转发两部分:类型层面让扩展类兼容原生DOM元素的所有类型定义,运行时把原生属性/方法的调用转发到内部持有的DOM元素上即可,完整实现如下:
// 类型合并:让FormElement<T>继承原生元素的所有类型定义,保证TS类型检查正常 export interface FormElement<T extends HTMLElement = HTMLElement> extends T {} export class FormElement<T extends HTMLElement = HTMLElement> { public element: T; constructor(selector: string) { const el = document.querySelector<T>(selector); if (!el) throw new Error(`找不到对应元素,选择器:${selector}`); this.element = el; // 运行时代理:把不在当前类的属性/方法调用转发到原生DOM元素 return new Proxy(this, { get(target, prop) { // 优先读取扩展类自身的属性/方法 if (prop in target) { return Reflect.get(target, prop); } // 读取原生元素的属性/方法 const originProp = Reflect.get(target.element, prop); // 原生方法需要绑定this到DOM元素,避免调用报错 if (typeof originProp === 'function') { return originProp.bind(target.element); } return originProp; }, set(target, prop, value) { // 赋值逻辑同理,优先给扩展类自身,否则赋值给原生元素 if (prop in target) { return Reflect.set(target, prop, value); } return Reflect.set(target.element, prop, value); } }); } public disable(): void { this.element.setAttribute('disabled', 'disabled'); } public enable(): void { this.element.removeAttribute('disabled'); } }
使用示例
和你期望的调用方式完全一致,自定义方法和原生方法/属性都可以直接调用:
class SomeComponent { private get nameInput(): FormElement<HTMLInputElement> { return new FormElement('input#company_msisdn') } private disableNameInput = (): void => { // 调用自定义扩展方法 this.nameInput.disable() } private initializeNameInput = (): void => { // 直接调用原生DOM方法 this.nameInput.addEventListener('change', this.onNameInputChange) // 直接访问原生DOM属性 console.log(this.nameInput.value) } private onNameInputChange = (e: Event) => { // 业务逻辑 } }
补充说明
- 该实现不会污染全局
HTMLElement原型,仅在显式使用FormElement的场景生效,无全局副作用 - 内置了元素空校验,找不到对应元素时会提前抛出错误,避免后续空指针异常
- 如果需要支持属性删除、遍历等更复杂的操作,可按需补充
Proxy的对应拦截方法
内容的提问来源于stack exchange,提问作者Sergio Belevskij
相关产品推荐
相关产品推荐

