跳到主要内容

扩展自定义组件

扩展 XphForm 表单项

扩展表单项

如果当前 XphForm 组件的所有表单项都满足不了你,xph-crud 还提供XphExtendCompPropsProvider来扩展表单项,你只需要使用XphExtendCompPropsProvider来包裹你的应用,并且为其提供一个表单项的映射对象即可,详细请看下方代码块:

import React from "react";
import { XphForm, XphExtendCompPropsProvider } from "xph-crud";

const MyButton = ({ children }) => {
return <button>{children}</button>;
};

const MyInput = ({ placeholder }) => {
return <input placeholder={placeholder}></input>;
};

/**
* 表单项的映射对象
*/
const myComponentMap = {
MyButton,
MyInput,
};

const ReactApp: React.FC = () => {
const props = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
items: [
{
name: "MyButton",
label: "MyButton",
component: "MyButton",
colProps: { span: 8 },
componentProps: {
children: "我是自定义的按钮",
},
},
{
name: "MyInput",
label: "MyInput",
component: "MyInput",
colProps: { span: 8 },
componentProps: {
placeholder: "我是自定义的输入框",
},
},
],
};

return (
<div style={{ minWidth: "1400px" }}>
<XphExtendCompPropsProvider
value={{ extendComp: { form: myComponentMap } }}
>
<XphForm {...props}></XphForm>
</XphExtendCompPropsProvider>
</div>
);
};

export default ReactApp;

扩展表单项的规范

import React from "react";
import {
XphForm,
IXphFormActionType,
XphExtendCompPropsProvider,
} from "xph-crud";

/** 自定义表单项的属性 */
interface IMyInputProps {
/** input边框的颜色 */
borderColor?: string;
/** 提示语 */
placeholder?: string;
/** onChange是默认透传进来的,如果表单model需要捕获当前自定义项的值,需要在自定义组件内部手动触发onChange事件,并且将值传递给其首个参数 */
onChange?: (...args) => void;
}

/**
* 自定义表单项
* (myInputProps就是初始化时候当前对应项的componentProps)
*/
const MyInput = (myInputProps: IMyInputProps) => {
const { borderColor, onChange, placeholder } = myInputProps;
const onInputChange = (e) => {
const {
target: { value },
} = e;
/** 手动触发onChange改变表单项对应的值,将表单需要捕获到的值传递到其首个参数 */
onChange && onChange(value);
};
return (
<input
onInput={onInputChange}
placeholder={placeholder}
style={{ borderColor: borderColor ? borderColor : "black" }}
/>
);
};

/**
* 表单项的映射对象
*/
const myComponentMap = {
MyInput,
};

const ReactApp: React.FC = () => {
const props = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
items: [
{
name: "MyInput",
label: "MyInput",
component: "MyInput",
colProps: { span: 8 },
componentProps: {
/** 此处的属性都会传递给myInputProps */
borderColor: "red",
placeholder: "我是自定义的输入框",
},
},
{
name: "Button",
label: "获取表单值",
component: "Button",
colProps: { span: 8 },
componentProps: {
children: "点击我获取表单的值",
onClick: async () => {
console.log(reactFormRef.current?.getFieldsValue(true));
},
},
},
],
};

const reactFormRef = React.useRef<IXphFormActionType>(null);

return (
<div style={{ minWidth: "1400px" }}>
<XphExtendCompPropsProvider
value={{ extendComp: { form: myComponentMap } }}
>
<XphForm ref={reactFormRef} {...props}></XphForm>
</XphExtendCompPropsProvider>
</div>
);
};

export default ReactApp;
提示

如果你使用的是 TypeSctipt,扩展表单项后,因为IXphFormProps类型中不包含你扩展表单项的类型,所以需要重新定义一下类型来使用,详细可看下方 ts 类型调整。

扩展 XphTable 单元格映射内容

扩展单元格映射内容

同理,XphTable中的映射内容也是可以自定义的,也是通过给XphExtendCompPropsProvider添加单元格映射对象即可的方式。

姓名
Simple Empty
No data
  • 共:0 条
  • 1
import React from "react";
import { XphTable, IXphMainProps, XphExtendCompPropsProvider } from "xph-crud";

/** 自定义单元格内容的属性 */
interface IMyTagProps {
children?: string;
borderColor?: string;
}

/** 自定义单元格内容组件 */
const MyTag = (
Comp: React.JSXElementConstructor<any>,
curCellFuncProps: { curComponentProps: IMyTagProps },
mainProps: IXphMainProps
) => {
const { curComponentProps } = curCellFuncProps;

const { borderColor = "blue", children = "" } = curComponentProps!;
return (
<div
style={{
display: "flex",
alignItems: "center",
flexWrap: "wrap",
border: `1px solid ${borderColor}`,
}}
>
<Comp {...mainProps} />
{children}
</div>
);
};

/**
* 单元格内容映射对象
*/
const myCellFuncComponentMap = {
myTag: MyTag,
};

const ReactApp: React.FC = () => {
const props: any = {
table: {
rowSelection: {
type: "checkbox",
},
fullHeight: true,
columns: [
{
title: "姓名",
dataIndex: "name",
key: "name",
cellFunc: [
{
component: "link",
componentProps: {
url: "https://www.taobao.com",
},
},
{
component: "myTag",
componentProps: {
// 此处的属性都会传递给curComponentProps
children: "随便加的内容",
borderColor: "orange",
},
},
],
},
],
autoPagination: true,
api: async (params) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{
key: "1",
name: "胡彦斌",
age: 32,
address: "西湖区湖底公园1号",
},
]);
}, 2000);
});
},
},
};

return (
<div style={{ minWidth: "800px", height: "300px" }}>
<XphExtendCompPropsProvider
value={{ extendComp: { tableCellFunc: myCellFuncComponentMap } }}
>
<XphTable {...props} />
</XphExtendCompPropsProvider>
</div>
);
};

export default ReactApp;

扩展单元格映射内容的规范

组件处理机制

内部的 CellFunc 组件会遍历 cellFunc 这个数组,逐步将最底层的 BottomCellFunc 组件处理成最终渲染在页面的组件,处理顺序如下:

组件渲染机制

由于是按顺序处理完再渲染,所以 cellFunc 数组映射的组件渲染是有顺序之分的,渲染顺序如下:

扩展规范

import React from "react";
import { IXphMainProps } from "xph-crud";

interface IMyTagProps {
children?: string;
borderColor?: string;
}

/**
* @params Comp - 上一次处理后的组件
* @params curCellFuncProps - 当前项相关属性
* @params mainProps - 透传给最底层组件的属性
*/
const MyTag = (
Comp: React.JSXElementConstructor<any>,
curCellFuncProps: { curComponentProps: IMyTagProps },
mainProps: IXphMainProps
) => {
/**
* curCellFuncProps是包含当前自定义项componentProps的参数,可以从中取到外部透传进来的属性进行业务代码编写
*/
const { curComponentProps } = curCellFuncProps;

const { borderColor = "blue", children = "" } = curComponentProps!;
return (
<div
style={{
display: "flex",
alignItems: "center",
flexWrap: "wrap",
border: `1px solid ${borderColor}`,
}}
>
{/**
1、Comp是保持渲染链的桥梁,只有当Comp组件被渲染时,才能保持渲染链不被中断,所以在写你的自定义组件时,这个Comp属性是必须使用在组件上的(当然特殊情况除外,除非你只想渲染这个自定义的组件)

2、mainProps是渲染链中渲染后方传递给最底层BottomCellFunc组件的属性,目的是为了使当前自定义组件能够影响到BottomCellFunc组件的事件和样式,所以mainProps是保持渲染链中事件和样式能够正确执行属性,它必须在扩展组件内部解构传递给Comp组件(注意:如果当前扩展的组件内部需要影响到底层BottomCellFunc,必须要保证其他映射组件的正常调用,XphTable内部的link组件就是一个很好的例子)
*/}
<Comp {...mainProps} />
{children}
</div>
);
};
注意

总的来说规范有三点:

  1. 必须保证扩展组件中的首个参数 Comp 被渲染来保持渲染链
  2. 必须保证扩展组件中的第三个参数 mainProps 解构传递给 Comp 组件
  3. 自定义组件在需要传递自己的 mainProps 给底层的 BottomCellFunc 组件时,必须保证其他映射组件的正常调用
提示

如果你使用的是 TypeSctipt,扩展单元格映射内容后,因为TXphTableProps类型中不包含你扩展的类型,所以需要重新定义一下类型来使用,详细可看下方 ts 类型调整。

扩展 XphActions 操作组映射内容

扩展操作组映射内容

同理,XphActions中的映射内容也是可以自定义的,也是通过给XphExtendCompPropsProvider添加操作组映射对象即可的方式。

import React from "react";
import { XphActions, XphExtendCompPropsProvider } from "xph-crud";

/**
* 自定义操作组内容的属性
* */
interface IMyButtonProps {
children: string;
onClick?: (e: any) => void;
}

/**
* 自定义操作组内容组件
*/
const MyButton = ({
componentProps,
component,
}: {
componentProps: IMyButtonProps;
component: "MyButton";
}) => {
console.log(component);
const { children, onClick } = componentProps;
return <button onClick={onClick}>{children}</button>;
};

/**
* 操作组映射对象
*/
const myActionsComponentMap = {
MyButton,
};

const ReactApp: React.FC = () => {
const props: any = {
type: "dashed",
max: 1,
items: [
{
component: "MyButton",
componentProps: {
// 此处的属性都会传递给myButtonProps
children: "我是自定义的按钮",
onClick: (e) => {
console.log(e);
},
},
},
],
};

return (
<div style={{ display: "flex", gap: "8px" }}>
<XphExtendCompPropsProvider
value={{ extendComp: { actions: myActionsComponentMap } }}
>
<XphActions {...props} />
</XphExtendCompPropsProvider>
</div>
);
};

export default ReactApp;
提示

如果你使用的是 TypeSctipt,扩展操作组映射内容后,因为IXphActionsProps类型中不包含你扩展的类型,所以需要重新定义一下类型来使用,详细可看下方 ts 类型调整。

ts 类型调整

如果你扩展了xph-crud中的映射组件,组件的属性类型需要你传入映射对象属性的泛型,否者组件的类型会对应不上。但是在这里我们建议你通过声明全局的类型,再使用全局的类型来进行约束,这样方便很多。

创建全局类型 INewXphFormProps

新建 xph-crud.d.ts 于项目中

/**
* xph-crud.d.ts
*/
import { IXphFormProps, IXphActionsProps, TXphTableProps } from "xph-crud";

/** 这是自定义表单项的属性映射,根据自己而定 */
interface MyFormComponentPropsMap {
MyInput: {
borderColor?: string;
onChange?: (...args) => void;
};
}

/** 若需自己扩展组件,可以在这里声明类型(声明后使用该类型定义变量才能获得扩展的组件类型) */
declare global {
/** 表单的映射 */
interface INewXphFormProps extends IXphFormProps<MyFormComponentPropsMap> {}
/** 操作组的映射 */
interface INewXphActionsProps
extends IXphActionsProps<{ MyComponentName: {} }> {}
/** 表格的映射 */
type TNewXphTableProps<T = unknown> = TXphTableProps<
T,
{
MyCellFuncComponentName: {};
},
{
MyActionsComponentName: {};
},
{
MyToolbarComponentName: {};
},
MyFormComponentPropsMap
>;
}

例子

import React from "react";
import { XphForm, XphExtendCompPropsProvider } from "xph-crud";

interface IMyInputProps {
borderColor?: string;
placeholder?: string;
onChange?: (...args) => void;
}

const MyInput = (myInputProps: IMyInputProps) => {
const { borderColor, onChange, placeholder } = myInputProps;
const onInputChange = (e) => {
const {
target: { value },
} = e;
onChange && onChange(value);
};
return (
<input
onInput={onInputChange}
placeholder={placeholder}
style={{ borderColor: borderColor ? borderColor : "black" }}
/>
);
};

const myComponentMap = {
MyInput,
};

const ReactApp: React.FC = () => {
const props: INewXphFormProps = {
labelCol: { span: 6 },
wrapperCol: { span: 18 },
items: [
{
name: "MyInput",
label: "MyInput",
component: "MyInput",
colProps: { span: 8 },
componentProps: {
borderColor: "red",
placeholder: "我是自定义的输入框",
},
},
],
};

return (
<div style={{ minWidth: "1400px" }}>
<XphExtendCompPropsProvider
value={{ extendComp: { form: myComponentMap } }}
>
<XphForm {...props}></XphForm>
</XphExtendCompPropsProvider>
</div>
);
};

export default ReactApp;