Tencent / omi

Web Components Framework - Web组件框架
http://omijs.org
Other
13.04k stars 1.24k forks source link

引入`formAssociated`和`hook`特性支持 #901

Closed zhangfisher closed 2 months ago

zhangfisher commented 2 months ago

本次PRomi引入formAssociatedhook特性支持,说明如下:

formAssociated

formAssociated特性目的为WebComponent引入表单功能,当开发扩展表单组件时需要此功能的支持。

使用方式:


@tag("my-input",{
   formAssociated:true          // 启用此功能
})
export default class MyInput extends Component {
    static props = {
        name:String,
        value:String
    } as any
    render(props:any){
        return <div><input name={props.name} value={props.value} type="text"/></div>
    }
}

然后在表单中就可以像普通标准input一样使用了,

<form>
      <my-input name="x" value={1}/>
      <my-input name="y" value={2}/>
      <my-input name="z" value={3}/>
</form>

组合表单字段:

以上在my-input组件内部仅嵌入一个标准input组件,现在也支持组合多个input,甚至是任意表单内容。

以下是一个my-ipaddress的组件,支持分别输入IP地址的四个部分。

@tag("my-ipaddress",{formAssociated:true})
export default class MyInput extends Component {
    static props = {
        name:{
            type:String,
            value:"ip"
        },
        value:String
    } as any

    f1= createRef()
    f2=createRef()
    f3=createRef()
    f4=createRef()

    getFieldValue(){
        return {
            // @ts-ignore
            [this.props.name]:`${this.f1.current.value}.${this.f2.current.value}.${this.f3.current.value}.${this.f4.current.value}`
        }            
    }
    render(){        
        return <div>
            <input ref={this.f1} name="f1" value="192" type="text"/>
            <input ref={this.f2}  name="f2" value="168" type="text"/>
            <input ref={this.f3} name="f3" value="0" type="text"/>
            <input ref={this.f4} name="f4" value="1" type="text"/>
        </div>
    }
} 

getFieldValue返回一个Record<string,any>,也就是form可以识别的表单字段,这样我们封装的WebCompoent就可以

其他说明

hook机制

在实现formAssociated特性时,需要在component.tsx源码中侵入修改:

但是考虑到formAssociated特性并不是所有WebComponent均需要的,所以直接修改Component.ts并不是好主意,最入是按需要注入,为此我引入hook机制,并且修改了@tag增加了options参数,可以按需注入相应的formAssociated功能。

通过引入hook机制,一些类似formAssociated功能的功能就可以比较方便地进行注入,并且与核心Component,ts解耦。

实现机制

hook机制并不是为组件开发者准备的,而为omi的源码贡献者准备的,其实现机制如下:

支持的hook

目前设计的hook类型包括type ComponentHookType = 'define' | 'initial' | 'connected' | 'disconnected'

define

在使用@tag封装组件调用define定义组件前运行,为此本次提交修改了tag装饰器,在运行define定义组件前,从组件类的static hooks中读取到所有define类型的hook,然后运行。

之所以要引入此define hook ,是因为在实现formAssociated特性时,需要提供static formAssociated=trueformAssociatedCallback/formDisabledCallback/formResetCallback等实例方法。当调用define创建webcomponent时,这些callback会被注册到DOM中,然后在组件被放到form内时调用。 这样,这些callback,只能直接声明在Component,而不能在组件实例化后动态注入。 因此,就必须引入define hook ,在调用define创建webcomponent前可以修改组件类.

`initial

在组件类构造时handleProps后调用,此时可以得到初始化的props,包含继承链的经过处理的props

connected

connectedCallback运行后调用

disconnected

disconnectedCallback运行后调用

其他说明