参考:https://juejin.cn/book/6945998773818490884/section/6950659615675645990
示例demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| export default () => { const form = React.useRef(null) const submit =()=>{ form.current.submitForm((formValue)=>{ console.log(formValue) }) } const reset = ()=>{ form.current.resetForm() } return <div className='box' > <Form ref={ form } > <FormItem name="name" label="我是" > <Input /> </FormItem> <FormItem name="mes" label="我想对大家说" > <Input /> </FormItem> </Form> <div className="btns" > <button className="searchbtn" onClick={ submit } >提交</button> <button className="concellbtn" onClick={ reset } >重置</button> </div> </div> }
|
Form 目标:
- 基于class component实现
- 负责管理 form store(表单数据存储对象)
- 能够识别 children 上的 FormItem 组件,并且只渲染它们
- 内置一些方法,外部能通过 ref 拿到,并且进行表单提交、验证等操作
实现:
无
内置一个object,或者搞个专门的class都行
通过FormItem的displayName或者其它标识,来判断是否为 FormItem;
并且重写 children 节点,只拿出来 FormItem,并且将改变 FormItem 绑定的表单字段的值的方法传给 FormItem。
基于 class 实现的,外界使用时ref可以直接拿到 class 上的方法。内部支持表单提交、验证等操作即可。
FormItem 目标:
- 基于class component实现
- 能识别内置的 Input / Checkbox / Radio 等组件,并且在状态改变时,将改变传给 Form
实现:
- 无
- 给 Input / Checkbox / Radio 等组件挂上 dispalyName 标识属性
Tab(Item)
示例
1 2 3 4 5 6 7 8 9 10 11
| <TabButtonList onChange={value => { setTab(value); submit(); }} activeKey={tab} > <TabButton key={TAB_TYPE.ALL}>{TAB_MAP[TAB_TYPE.ALL]}</TabButton> <TabButton key={TAB_TYPE.INWORK}>{TAB_MAP[TAB_TYPE.INWORK]}</TabButton> <TabButton key={TAB_TYPE.HASWORK}>{TAB_MAP[TAB_TYPE.HASWORK]}</TabButton> </TabButtonList>
|
区别
和Form、FormItem相比,行为没有那么复杂,同时也不需要像FormItem那样,内部还得判断Input、Select等组件。
TabItem实现
- 响应点击选中样式
- 相应点击事件
- 需要通过
displayName
挂入标识,方便父级 TabButtonList
判断
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| import React from 'react'; import classnames from 'classnames'; import styles from './index.module.scss'; import { TabButtonProps, TabButtonListProps } from './types';
const TYPE_NAME = { tabButton: '__tab_button', } as const;
export const TabButton = React.memo((props: TabButtonProps) => { const { children, clicked } = props;
const renderChildren = () => { if (typeof children === 'function') { return children(); } return children; };
return ( <div className={classnames(styles.tabButton, { [styles.active]: clicked, })} onClick={(props as any)?.onClick || (() => {})} > {renderChildren()} </div> ); }); TabButton.displayName = TYPE_NAME.tabButton;
|
- 遍历所有的子元素,挑选
TabButton
组件,跳过其他组件
- 根据外面传入的
activeKey
:判定当前的 TabButton
组件是否为选中状态,并且选中组件跳过 click
回diao
代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
export const TabButtonList = React.memo((props: TabButtonListProps) => { const { className, children, activeKey, onChange, style } = props;
const childList: ReturnType<typeof React.cloneElement>[] = []; React.Children.forEach(children, (child: any) => { if (child.type.displayName === TYPE_NAME.tabButton) { const { props: { children: cc }, key: cKey } = child; const childCopy = React.cloneElement(child, { key: cKey, clicked: cKey === activeKey, onClick: () => { if (typeof onChange === 'function' && cKey !== activeKey) { onChange(cKey); } }, }, cc); childList.push(childCopy); } });
return ( <div className={className} style={style}> {childList} </div> ); });
|