实现了一个按钮组,loading按钮,确认按钮和加载按钮.
npm i --save @kne/button-group@kne/button-group 是一个 React 按钮组件库,提供了一系列功能丰富的按钮组件,用于简化常见的按钮交互场景。该库专注于提供自适应布局、加载状态管理、确认操作和数据请求等功能,使开发者能够快速实现各种复杂的按钮交互需求。
自适应按钮组组件,能够根据容器宽度自动调整显示的按钮数量。当容器宽度不足以显示所有按钮时,会自动将多余的按钮放入下拉菜单中,确保界面布局美观且功能完整。
主要特性:
- 自动适应容器宽度
- 支持紧凑模式(Space.Compact)
- 支持链接样式(适用于表格操作列)
- 可指定显示的按钮数量
- 支持禁用、隐藏状态
- 支持自定义按钮渲染
- 支持禁用按钮的工具提示
适用场景:
- 操作栏、工具栏
- 表格操作列
- 面板标题栏
- 任何需要自适应按钮布局的场景
封装了加载状态的按钮组件,简化了异步操作的处理。通过内置的状态管理,在异步操作执行期间自动显示加载状态,提升用户体验。同时提供了 useLoading hook,方便在其他组件中复用加载状态管理逻辑。
主要特性:
- 自动管理加载状态
- 支持自定义加载文案
- 自动处理错误情况
- 支持 loading 属性手动控制
- 提供的 useLoading Hook 可在其他组件使用
适用场景:
- 表单提交按钮
- 数据导出按钮
- 任何需要异步操作的按钮
- 非按钮组件的异步状态管理
带有确认功能的按钮组件,支持弹窗确认(Popconfirm)和模态框确认(Modal)两种模式。适用于需要用户二次确认的操作,如删除、提交等重要操作。同时提供了 ConfirmLink 和 ConfirmText 变体,以及 withConfirm 高阶组件,满足不同场景的确认需求。
主要特性:
- 支持 Popconfirm 和 Modal 两种确认模式
- 支持危险操作样式(红色按钮)
- 可自定义确认和取消按钮文案
- 提供 ConfirmLink 和 ConfirmText 变体
- 确认时自动显示加载状态
适用场景:
- 删除操作
- 数据提交
- 审核操作
- 表格行操作(使用 ConfirmLink/ConfirmText)
- 任何需要用户二次确认的操作
集成了数据请求功能的按钮组件,基于 @kne/react-fetch 库实现。可以直接处理 API 请求,并在请求过程中自动管理加载状态,简化了数据交互的实现。
主要特性:
- 自动管理请求加载状态
- 支持请求成功/失败回调
- 支持参数传递
- 支持请求拦截(beforeFetch)
- 基于 @kne/react-fetch 实现
适用场景:
- 数据刷新按钮
- 文件导出按钮
- API 请求按钮
- 任何按钮触发的数据请求场景
页面底部按钮区域组件,可以自动计算高度并设置 CSS 变量,方便页面布局和样式调整。在小屏幕下,会自动将内容渲染到 body,确保按钮始终可见。
主要特性:
- 自动计算高度并设置 CSS 变量
- 响应式设计,小屏幕下固定到底部
- 支持多种布局方式(居中、左右分布等)
- 适用于表单页面的底部操作区
适用场景:
- 表单页面底部操作按钮
- 详情页面底部操作按钮
- 对话框底部按钮
- 任何需要固定在底部的操作按钮区域
ButtonGroup (自适应布局)
├── LoadingButton (加载状态)
├── ConfirmButton (确认功能)
│ ├── ConfirmLink (链接变体)
│ └── ConfirmText (文本变体)
└── FetchButton (数据请求)
└── 基于 LoadingButton
ButtonFooter (底部固定区域)
该组件库的设计理念是通过封装常见的按钮交互模式,提供开箱即用的解决方案,同时保持足够的灵活性和可扩展性:
-
关注点分离:每个组件专注于解决特定的问题,如 ButtonGroup 专注于布局,LoadingButton 专注于状态管理。
-
组合优于继承:通过组合不同的功能组件,可以实现复杂的交互需求,如 FetchButton 就是 LoadingButton 与数据请求功能的组合。
-
声明式 API:提供简洁明了的 API,使开发者能够以声明式的方式描述 UI 和交互行为。
-
渐进式增强:基础组件可以独立使用,也可以与其他组件组合使用,实现更复杂的功能。
-
用户体验优先:注重细节,如自适应布局、加载状态反馈等,提升最终用户的使用体验。
- 自适应布局:根据容器宽度自动调整按钮显示方式
- 加载状态管理:简化异步操作的加载状态处理
- 操作确认:提供多种确认模式,增强用户操作安全性
- 数据请求集成:简化按钮与后端 API 的交互
- 国际化支持:内置中英文语言包
- 高度可定制:组件提供丰富的配置选项
- 响应式设计:适配不同屏幕尺寸
- TypeScript 友好:完整的类型定义
- ButtonGroup 基础用法
- ButtonGroup 能够根据容器宽度自动调整显示的按钮数量,并将多余的按钮放入下拉菜单中。适用于操作栏、工具栏等场景。
- _ButtonGroup(@kne/current-lib_button-group)[import * as _ButtonGroup from "@kne/button-group"],antd(antd)
const { default: ButtonGroup } = _ButtonGroup;
const { Flex, Button, Space, Typography } = antd;
const { useState } = React;
const { Text } = Typography;
// 基础用法 - 自动适应容器宽度
const BasicExample = () => {
const [width, setWidth] = useState(300);
return (
<Flex gap={16} vertical>
<Text type="secondary">调整容器宽度查看自适应效果</Text>
<Flex gap={8}>
<div style={{ width: `${width}px`, padding: '12px', background: '#f5f5f5', borderRadius: '8px' }}>
<ButtonGroup
list={[
{ type: 'primary', children: '新建' },
{ type: 'default', children: '编辑' },
{ type: 'default', children: '导出' },
{ type: 'default', children: '打印' },
{ children: '更多操作1', message: '确定执行吗?' },
{ children: '更多操作2', message: '确定执行吗?' }
]}
/>
</div>
</Flex>
<Space>
<Button onClick={() => setWidth(w => Math.max(200, w - 50))}>减少宽度</Button>
<Button onClick={() => setWidth(w => Math.min(600, w + 50))}>增加宽度</Button>
</Space>
</Flex>
);
};
// 紧凑模式
const CompactExample = () => {
return (
<Flex gap={16} vertical>
<Text type="secondary">紧凑模式(适用于工具栏)</Text>
<ButtonGroup
compact
list={[
{ type: 'primary', children: '保存' },
{ children: '撤销' },
{ children: '重做' },
{ children: '删除', isDelete: true }
]}
/>
</Flex>
);
};
// 链接样式 - 更多按钮
const LinkStyleExample = () => {
const [width, setWidth] = useState(200);
return (
<Flex gap={16} vertical>
<Text type="secondary">链接样式(适用于表格操作栏)</Text>
<div style={{ width: `${width}px` }}>
<ButtonGroup
moreType="link"
list={[
{ children: '查看', type: 'link' },
{ children: '编辑', type: 'link' },
{ children: '删除', type: 'link', isDelete: true, message: '确定删除吗?' },
{ children: '审核', type: 'link' },
{ children: '驳回', type: 'link' }
]}
/>
</div>
<Space>
<Button onClick={() => setWidth(w => Math.max(150, w - 30))}>-</Button>
<Button onClick={() => setWidth(w => Math.min(400, w + 30))}>+</Button>
</Space>
</Flex>
);
};
// 指定显示数量
const FixedLengthExample = () => {
const [showLength, setShowLength] = useState(2);
return (
<Flex gap={16} vertical>
<Text type="secondary">指定显示按钮数量(showLength)</Text>
<Space>
<Button
type={showLength === 1 ? 'primary' : 'default'}
onClick={() => setShowLength(1)}
>
显示1个
</Button>
<Button
type={showLength === 2 ? 'primary' : 'default'}
onClick={() => setShowLength(2)}
>
显示2个
</Button>
<Button
type={showLength === 3 ? 'primary' : 'default'}
onClick={() => setShowLength(3)}
>
显示3个
</Button>
</Space>
<ButtonGroup
showLength={showLength}
list={[
{ type: 'primary', children: '主要操作' },
{ children: '次要操作1' },
{ children: '次要操作2' },
{ children: '次要操作3' },
{ children: '次要操作4' }
]}
/>
</Flex>
);
};
// 自定义渲染函数
const CustomRenderExample = () => {
const CustomButton = (props) => (
<Button {...props} style={{ borderRadius: '4px' }}>
{props.children}
</Button>
);
return (
<Flex gap={16} vertical>
<Text type="secondary">自定义渲染(支持函数式配置)</Text>
<div style={{ padding: '12px', background: '#f5f5f5', borderRadius: '8px', width: '280px' }}>
<ButtonGroup
moreType="link"
list={[
(props) => <CustomButton {...props} type="primary">自定义按钮</CustomButton>,
(props) => <CustomButton {...props}>按钮2</CustomButton>,
(props) => <CustomButton {...props}>按钮3</CustomButton>,
(props) => <CustomButton {...props}>按钮4</CustomButton>
]}
/>
</div>
</Flex>
);
};
// 禁用状态与隐藏
const StateExample = () => {
const [disabled, setDisabled] = useState(true);
const [hidden, setHidden] = useState(true);
return (
<Flex gap={16} vertical>
<Text type="secondary">禁用与隐藏状态</Text>
<Space>
<Button onClick={() => setDisabled(!disabled)}>
{disabled ? '启用' : '禁用'}操作3
</Button>
<Button onClick={() => setHidden(!hidden)}>
{hidden ? '显示' : '隐藏'}操作4
</Button>
</Space>
<ButtonGroup
list={[
{ type: 'primary', children: '操作1' },
{ children: '操作2' },
{ children: '操作3', disabled },
{ children: '操作4', hidden },
{ children: '操作5', message: '确定吗?' }
]}
/>
</Flex>
);
};
// 工具提示
const TooltipExample = () => {
return (
<Flex gap={16} vertical>
<Text type="secondary">禁用按钮提示(tooltipProps)</Text>
<ButtonGroup
list={[
{ type: 'primary', children: '可用操作' },
{
children: '已禁用操作',
disabled: true,
tooltipProps: {
title: '此操作暂时不可用,请先完成前置步骤',
placement: 'bottom'
}
},
{
children: '需要权限',
disabled: true,
tooltipProps: {
title: '您没有执行此操作的权限',
placement: 'bottom'
}
}
]}
/>
</Flex>
);
};
const BaseExample = () => {
return (
<Space direction="vertical" size="large">
<Typography.Title level={3}>ButtonGroup 自适应按钮组</Typography.Title>
<Typography.Paragraph>
ButtonGroup 是一个自适应按钮组组件,能够根据容器宽度自动调整显示的按钮数量,
多余的按钮会放入下拉菜单中。适用于操作栏、工具栏、表格操作列等场景。
</Typography.Paragraph>
<Flex vertical gap={32}>
<div>
<Typography.Title level={4}>基础用法</Typography.Title>
<BasicExample />
</div>
<div>
<Typography.Title level={4}>紧凑模式</Typography.Title>
<CompactExample />
</div>
<div>
<Typography.Title level={4}>链接样式</Typography.Title>
<LinkStyleExample />
</div>
<div>
<Typography.Title level={4}>指定显示数量</Typography.Title>
<FixedLengthExample />
</div>
<div>
<Typography.Title level={4}>自定义渲染</Typography.Title>
<CustomRenderExample />
</div>
<div>
<Typography.Title level={4}>禁用与隐藏</Typography.Title>
<StateExample />
</div>
<div>
<Typography.Title level={4}>禁用提示</Typography.Title>
<TooltipExample />
</div>
</Flex>
</Space>
);
};
render(<BaseExample />);- LoadingButton 加载按钮
- LoadingButton 封装了加载状态,简化异步操作的处理。点击按钮时自动显示加载状态,避免重复提交。
- _ButtonGroup(@kne/current-lib_button-group)[import * as _ButtonGroup from "@kne/button-group"],antd(antd)
const { LoadingButton, useLoading } = _ButtonGroup;
const { Space, Button, Typography, message, Card, Alert, Flex } = antd;
const { useState } = React;
// 基础用法 - 自动加载状态
const BasicExample = () => {
const handleClick = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('操作成功!');
resolve();
}, 1500);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">点击按钮,自动管理加载状态</Typography.Text>
<Space wrap>
<LoadingButton type="primary" onClick={handleClick}>
保存数据
</LoadingButton>
<LoadingButton onClick={handleClick}>提交审核</LoadingButton>
<LoadingButton danger onClick={handleClick}>删除</LoadingButton>
</Space>
</Space>
);
};
// 自定义加载文案
const CustomTextExample = () => {
const handleClick = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('上传完成');
resolve();
}, 2000);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">使用函数自定义加载时的文案</Typography.Text>
<Space>
<LoadingButton onClick={handleClick}>
{(isLoading) => (isLoading ? '正在上传...' : '上传文件')}
</LoadingButton>
<LoadingButton onClick={handleClick} type="primary">
{(isLoading) => (isLoading ? '提交中...' : '提交订单')}
</LoadingButton>
</Space>
</Space>
);
};
// 错误处理
const ErrorExample = () => {
const [shouldFail, setShouldFail] = useState(false);
const handleClick = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
message.error('操作失败,请重试');
reject(new Error('操作失败'));
} else {
message.success('操作成功');
resolve();
}
}, 1000);
});
};
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
演示错误处理:加载状态会自动解除
</Typography.Text>
<Space>
<Button onClick={() => setShouldFail(!shouldFail)}>
{shouldFail ? '切换为成功' : '切换为失败'}
</Button>
</Space>
<Space>
<LoadingButton onClick={handleClick}>
{shouldFail ? '会失败的操作' : '会成功的操作'}
</LoadingButton>
</Space>
{shouldFail && <Alert message="当前设置为失败模式" type="warning" />}
</Space>
);
};
// 手动控制加载状态
const ManualExample = () => {
const [loading, setLoading] = useState(false);
const handleClick = () => {
setLoading(true);
setTimeout(() => {
setLoading(false);
message.success('手动控制加载完成');
}, 2000);
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">通过 loading 属性手动控制加载状态</Typography.Text>
<LoadingButton loading={loading} onClick={handleClick}>
手动控制加载
</LoadingButton>
</Space>
);
};
// useLoading Hook 示例
const UseLoadingExample = () => {
const { isLoading, callback } = useLoading(() => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('Hook 模式操作完成');
resolve();
}, 1500);
});
});
return (
<Card title="useLoading Hook" style={{ width: 400 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
在非按钮组件中使用 useLoading 管理异步状态
</Typography.Text>
<Space>
<Button onClick={callback} loading={isLoading}>
使用 Hook
</Button>
<Button onClick={() => {}}>
独立按钮(不受影响)
</Button>
</Space>
{isLoading && (
<Alert message="当前状态:加载中" type="info" showIcon />
)}
</Space>
</Card>
);
};
// 不同按钮类型
const ButtonTypesExample = () => {
const handleClick = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('完成');
resolve();
}, 1000);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">支持所有 Ant Design Button 类型</Typography.Text>
<Space wrap>
<LoadingButton type="primary" onClick={handleClick}>Primary</LoadingButton>
<LoadingButton type="default" onClick={handleClick}>Default</LoadingButton>
<LoadingButton type="dashed" onClick={handleClick}>Dashed</LoadingButton>
<LoadingButton type="link" onClick={handleClick}>Link</LoadingButton>
<LoadingButton type="text" onClick={handleClick}>Text</LoadingButton>
</Space>
<Space wrap>
<LoadingButton type="primary" ghost onClick={handleClick}>Primary Ghost</LoadingButton>
<LoadingButton type="default" ghost onClick={handleClick}>Default Ghost</LoadingButton>
</Space>
</Space>
);
};
// 图标按钮
const IconExample = () => {
const handleClick = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('操作完成');
resolve();
}, 1200);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">支持图标</Typography.Text>
<Space>
<LoadingButton type="primary" icon={<span>⬆️</span>} onClick={handleClick}>
上传
</LoadingButton>
<LoadingButton icon={<span>⬇️</span>} onClick={handleClick}>
下载
</LoadingButton>
<LoadingButton danger icon={<span>🗑️</span>} onClick={handleClick}>
删除
</LoadingButton>
</Space>
</Space>
);
};
// 实际应用场景 - 表单提交
const FormSubmitExample = () => {
const handleSubmit = async () => {
// 模拟表单验证
await new Promise(resolve => setTimeout(resolve, 500));
// 模拟 API 请求
await new Promise((resolve) => {
setTimeout(() => {
message.success('表单提交成功!');
resolve();
}, 1500);
});
};
return (
<Card title="表单提交场景" style={{ width: 400 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
点击提交按钮,自动防止重复提交
</Typography.Text>
<Space>
<LoadingButton type="primary" onClick={handleSubmit}>
提交表单
</LoadingButton>
<Button onClick={() => message.info('已取消')}>取消</Button>
</Space>
</Space>
</Card>
);
};
const BaseExample = () => {
return (
<Space direction="vertical" size="large">
<Typography.Title level={3}>LoadingButton 加载按钮</Typography.Title>
<Typography.Paragraph>
LoadingButton 封装了加载状态,简化异步操作的处理。点击按钮时自动显示加载状态,
避免重复提交,同时提供 useLoading Hook 供其他组件使用。
</Typography.Paragraph>
<Flex vertical gap={32}>
<div>
<Typography.Title level={4}>基础用法</Typography.Title>
<BasicExample />
</div>
<div>
<Typography.Title level={4}>自定义加载文案</Typography.Title>
<CustomTextExample />
</div>
<div>
<Typography.Title level={4}>错误处理</Typography.Title>
<ErrorExample />
</div>
<div>
<Typography.Title level={4}>手动控制加载状态</Typography.Title>
<ManualExample />
</div>
<div>
<Typography.Title level={4}>useLoading Hook</Typography.Title>
<UseLoadingExample />
</div>
<div>
<Typography.Title level={4}>不同按钮类型</Typography.Title>
<ButtonTypesExample />
</div>
<div>
<Typography.Title level={4}>图标按钮</Typography.Title>
<IconExample />
</div>
<div>
<Typography.Title level={4}>实际应用场景</Typography.Title>
<FormSubmitExample />
</div>
</Flex>
</Space>
);
};
render(<BaseExample />);- ConfirmButton 确认按钮
- ConfirmButton 带有确认功能,支持弹窗确认和模态框确认两种模式。适用于删除、提交等重要操作。
- _ButtonGroup(@kne/current-lib_button-group)[import * as _ButtonGroup from "@kne/button-group"],antd(antd)
const { ConfirmButton, ConfirmLink, ConfirmText } = _ButtonGroup;
const { Flex, Space, Typography, message, Card, List, Tag, Button } = antd;
const { useState } = React;
// 基础用法 - Popconfirm 模式
const BasicExample = () => {
const handleDelete = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('删除成功');
resolve();
}, 500);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">
Popconfirm 模式(气泡确认框),适用于快速确认
</Typography.Text>
<Space>
<ConfirmButton message="确定要删除吗?" onClick={handleDelete}>
删除
</ConfirmButton>
<ConfirmButton message="确定要提交吗?" onClick={handleDelete}>
提交
</ConfirmButton>
</Space>
</Space>
);
};
// Modal 模式
const ModalExample = () => {
const handleSubmit = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('提交成功');
resolve();
}, 500);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">
Modal 模式(模态框),适用于重要操作或长内容提示
</Typography.Text>
<Space>
<ConfirmButton
isModal
message="此操作将永久删除该数据,删除后无法恢复。确定要继续吗?"
onClick={handleSubmit}
>
删除数据
</ConfirmButton>
<ConfirmButton
isModal
title="提交确认"
message="提交后数据将进入审核流程,确认要提交吗?"
onClick={handleSubmit}
>
提交审核
</ConfirmButton>
</Space>
</Space>
);
};
// 危险操作样式
const DangerExample = () => {
const handleDelete = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('已删除');
resolve();
}, 500);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">
使用 isDelete 标识危险操作(红色按钮)
</Typography.Text>
<Space>
<ConfirmButton
danger
message="确定删除吗?"
onClick={handleDelete}
>
普通按钮
</ConfirmButton>
<ConfirmButton
isDelete
message="确定删除吗?"
onClick={handleDelete}
>
删除按钮
</ConfirmButton>
<ConfirmButton
isDelete
isModal
message="此操作无法撤销,确定要继续吗?"
onClick={handleDelete}
>
删除(Modal)
</ConfirmButton>
</Space>
</Space>
);
};
// 自定义确认文案
const CustomTextExample = () => {
const handleAction = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('操作完成');
resolve();
}, 500);
});
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">自定义确认和取消按钮文案</Typography.Text>
<Space>
<ConfirmButton
message="确定要执行此操作吗?"
okText="确认执行"
cancelText="暂不执行"
onClick={handleAction}
>
自定义文案
</ConfirmButton>
<ConfirmButton
isModal
title="操作确认"
message="请确认是否继续执行此操作"
okText="是,继续"
cancelText="否,取消"
onClick={handleAction}
>
Modal 自定义文案
</ConfirmButton>
</Space>
</Space>
);
};
// ConfirmLink 和 ConfirmText
const LinkAndTextExample = () => {
const handleAction = () => {
message.success('操作成功');
return Promise.resolve();
};
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
ConfirmLink 和 ConfirmText 变体,适用于表格行操作等场景
</Typography.Text>
<List
bordered
style={{ width: 400 }}
dataSource={[
{ id: 1, name: '数据项 A', status: '已提交' },
{ id: 2, name: '数据项 B', status: '草稿' },
{ id: 3, name: '数据项 C', status: '已审核' }
]}
renderItem={(item) => (
<List.Item
actions={[
<ConfirmLink key="edit" message="确定编辑吗?" onClick={handleAction}>
编辑
</ConfirmLink>,
<ConfirmLink key="delete" isDelete message="确定删除吗?" onClick={handleAction}>
删除
</ConfirmLink>
]}
>
<List.Item.Meta
title={item.name}
description={<Tag color={item.status === '已提交' ? 'blue' : 'default'}>{item.status}</Tag>}
/>
</List.Item>
)}
/>
<Space>
<ConfirmText onClick={handleAction}>纯文本确认</ConfirmText>
<Typography.Text type="secondary">|</Typography.Text>
<ConfirmText isDelete onClick={handleAction}>删除</ConfirmText>
</Space>
</Space>
);
};
// 禁用状态
const DisabledExample = () => {
const [disabled, setDisabled] = useState(true);
const handleDelete = () => {
message.success('已删除');
return Promise.resolve();
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">禁用状态下不会触发确认</Typography.Text>
<Space>
<Button onClick={() => setDisabled(!disabled)}>
{disabled ? '启用' : '禁用'}
</Button>
</Space>
<Space>
<ConfirmButton disabled={disabled} message="确定删除吗?" onClick={handleDelete}>
删除
</ConfirmButton>
<ConfirmLink disabled={disabled} message="确定删除吗?" onClick={handleDelete}>
删除
</ConfirmLink>
</Space>
</Space>
);
};
// 实际应用场景 - 表格操作
const TableActionExample = () => {
const handleEdit = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('进入编辑模式');
resolve();
}, 300);
});
};
const handleDelete = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('已删除');
resolve();
}, 300);
});
};
const handleAudit = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success('审核通过');
resolve();
}, 300);
});
};
return (
<Card title="实际应用:表格操作栏" style={{ width: 500 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
模拟表格中的操作按钮,包含不同的确认方式
</Typography.Text>
<List
bordered
dataSource={[
{ id: 1, name: '产品 A', price: '¥99.00' },
{ id: 2, name: '产品 B', price: '¥199.00' }
]}
renderItem={(item) => (
<List.Item
actions={[
<ConfirmButton key="edit" type="link" message={`确定编辑 ${item.name} 吗?`} onClick={handleEdit}>
编辑
</ConfirmButton>,
<ConfirmButton key="audit" type="link" message={`确定通过 ${item.name} 的审核吗?`} onClick={handleAudit}>
审核
</ConfirmButton>,
<ConfirmButton
key="delete"
type="link"
danger
message={`确定删除 ${item.name} 吗?此操作无法撤销。`}
onClick={handleDelete}
>
删除
</ConfirmButton>
]}
>
<List.Item.Meta
title={item.name}
description={item.price}
/>
</List.Item>
)}
/>
</Space>
</Card>
);
};
// 批量操作
const BatchExample = () => {
const [selectedCount, setSelectedCount] = useState(0);
const handleBatchDelete = () => {
return new Promise((resolve) => {
setTimeout(() => {
message.success(`已删除 ${selectedCount} 条数据`);
setSelectedCount(0);
resolve();
}, 500);
});
};
return (
<Card title="批量操作场景" style={{ width: 450 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Space>
<Typography.Text type="secondary">已选择:</Typography.Text>
<Typography.Text strong>{selectedCount} 项</Typography.Text>
<Button size="small" onClick={() => setSelectedCount(Math.floor(Math.random() * 10))}>
随机选择
</Button>
</Space>
<Space>
<ConfirmButton
type="primary"
disabled={selectedCount === 0}
isModal
title="批量删除确认"
message={`确定要删除选中的 ${selectedCount} 条数据吗?此操作无法撤销。`}
onClick={handleBatchDelete}
>
批量删除
</ConfirmButton>
<ConfirmButton
disabled={selectedCount === 0}
message={`确定导出选中的 ${selectedCount} 条数据吗?`}
onClick={() => {
message.success(`正在导出 ${selectedCount} 条数据`);
return Promise.resolve();
}}
>
导出
</ConfirmButton>
</Space>
</Space>
</Card>
);
};
const BaseExample = () => {
return (
<Space direction="vertical" size="large">
<Typography.Title level={3}>ConfirmButton 确认按钮</Typography.Title>
<Typography.Paragraph>
ConfirmButton 提供确认功能,支持 Popconfirm(气泡确认框)和 Modal(模态框)两种模式。
还提供 ConfirmLink 和 ConfirmText 变体,以及 withConfirm 高阶组件。
</Typography.Paragraph>
<Flex vertical gap={32}>
<div>
<Typography.Title level={4}>Popconfirm 模式</Typography.Title>
<BasicExample />
</div>
<div>
<Typography.Title level={4}>Modal 模式</Typography.Title>
<ModalExample />
</div>
<div>
<Typography.Title level={4}>危险操作样式</Typography.Title>
<DangerExample />
</div>
<div>
<Typography.Title level={4}>自定义文案</Typography.Title>
<CustomTextExample />
</div>
<div>
<Typography.Title level={4}>Link 和 Text 变体</Typography.Title>
<LinkAndTextExample />
</div>
<div>
<Typography.Title level={4}>禁用状态</Typography.Title>
<DisabledExample />
</div>
<div>
<Typography.Title level={4}>实际应用场景</Typography.Title>
<TableActionExample />
</div>
<div>
<Typography.Title level={4}>批量操作</Typography.Title>
<BatchExample />
</div>
</Flex>
</Space>
);
};
render(<BaseExample />);- FetchButton 请求按钮
- FetchButton 集成了数据请求功能,自动管理加载状态和请求流程。适用于按钮触发 API 请求的场景。
- _ButtonGroup(@kne/current-lib_button-group)[import * as _ButtonGroup from "@kne/button-group"],(@kne/current-lib_button-group/dist/index.css),antd(antd)
const { FetchButton } = _ButtonGroup;
const { Space, Typography, message, Card, Alert, Form, Input, Select, Button, Flex } = antd;
const { useState } = React;
// 基础用法
const BasicExample = () => {
const handleSuccess = ({ data }) => {
message.success(`获取数据成功: ${data}`);
};
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
点击按钮触发 API 请求,自动管理加载状态
</Typography.Text>
<FetchButton
type="primary"
api={{
loader: async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: '用户信息数据' });
}, 1500);
});
}
}}
onClick={handleSuccess}
>
获取用户信息
</FetchButton>
</Space>
);
};
// 带参数请求
const WithParamsExample = () => {
const [userId, setUserId] = useState('1');
const handleSuccess = ({ data }) => {
message.success(`获取成功: ${JSON.stringify(data)}`);
};
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">传递参数到 API 请求</Typography.Text>
<Space>
<Select
value={userId}
onChange={setUserId}
style={{ width: 120 }}
options={[
{ value: '1', label: '用户1' },
{ value: '2', label: '用户2' },
{ value: '3', label: '用户3' }
]}
/>
<FetchButton
params={{ userId }}
api={{
loader: async ({ params }) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: { userId: params.userId, name: `用户${params.userId}`, role: '管理员' } });
}, 1000);
});
}
}}
onClick={handleSuccess}
>
获取用户详情
</FetchButton>
</Space>
</Space>
);
};
// 成功和失败回调
const CallbackExample = () => {
const [status, setStatus] = useState('');
const [shouldFail, setShouldFail] = useState(false);
const handleSuccess = ({ data }) => {
setStatus('success');
message.success('数据加载成功');
console.log('成功数据:', data);
};
const handleError = (error) => {
setStatus('error');
message.error('数据加载失败');
console.error('错误信息:', error);
};
return (
<Card title="成功与失败回调" style={{ width: 450 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Space>
<Button onClick={() => setShouldFail(!shouldFail)} size="small">
{shouldFail ? '切换为成功' : '切换为失败'}
</Button>
</Space>
<FetchButton
type="primary"
api={{
loader: async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (shouldFail) {
reject(new Error('模拟的请求失败'));
} else {
resolve({ data: { message: '请求成功', timestamp: Date.now() } });
}
}, 1000);
});
}
}}
onSuccess={handleSuccess}
onError={handleError}
>
{shouldFail ? '失败请求' : '成功请求'}
</FetchButton>
{status === 'success' && <Alert message="上次请求:成功" type="success" />}
{status === 'error' && <Alert message="上次请求:失败" type="error" />}
</Space>
</Card>
);
};
// 导出文件场景
const ExportExample = () => {
const handleExport = ({ data }) => {
message.success(`导出成功: ${data.url}`);
};
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">模拟文件导出场景</Typography.Text>
<Space>
<FetchButton
api={{
loader: async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: { url: '/download/report.xlsx', size: '2.5MB' } });
}, 2000);
});
}
}}
onClick={handleExport}
>
导出报表
</FetchButton>
<FetchButton
type="primary"
api={{
loader: async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: { url: '/download/data.csv', size: '1.2MB' } });
}, 1500);
});
}
}}
onClick={handleExport}
>
导出 CSV
</FetchButton>
</Space>
</Space>
);
};
// 表单提交场景
const FormSubmitExample = () => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const [submittedData, setSubmittedData] = useState(null);
const handleSubmit = ({ data }) => {
setSubmittedData(data);
message.success('表单提交成功');
};
const onFinish = async () => {
try {
const values = await form.validateFields();
setLoading(true);
// 使用 FetchButton 内部处理,这里只是演示
await new Promise(resolve => setTimeout(resolve, 1000));
setLoading(false);
message.success('验证通过');
} catch (error) {
message.error('请检查表单内容');
}
};
return (
<Card title="表单提交场景" style={{ width: 450 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Form
form={form}
layout="vertical"
>
<Form.Item
name="username"
label="用户名"
rules={[{ required: true, message: '请输入用户名' }]}
>
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item
name="email"
label="邮箱"
rules={[{ required: true, message: '请输入邮箱' }]}
>
<Input placeholder="请输入邮箱" />
</Form.Item>
</Form>
<Space>
<FetchButton
type="primary"
api={{
loader: async ({ params }) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: { id: 123, ...params, createTime: new Date().toISOString() } });
}, 1500);
});
}
}}
beforeFetch={() => {
const values = form.getFieldsValue();
if (!values.username || !values.email) {
message.error('请填写完整信息');
return false;
}
return true;
}}
onClick={handleSubmit}
>
提交表单
</FetchButton>
<Button onClick={() => form.resetFields()}>重置</Button>
</Space>
{submittedData && (
<Alert
message="提交成功"
description={JSON.stringify(submittedData, null, 2)}
type="success"
/>
)}
</Space>
</Card>
);
};
// 刷新数据场景
const RefreshExample = () => {
const [data, setData] = useState(null);
const [lastRefresh, setLastRefresh] = useState(null);
const handleRefresh = ({ data: newData }) => {
console.log(newData);
setData(newData);
setLastRefresh(new Date().toLocaleTimeString());
message.success('数据已更新');
};
return (
<Card title="刷新数据场景" style={{ width: 450 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Space>
<Typography.Text type="secondary">上次刷新:</Typography.Text>
<Typography.Text>{lastRefresh || '从未刷新'}</Typography.Text>
</Space>
<FetchButton
api={{
loader: async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
users: [
{ id: 1, name: '用户A', status: '在线' },
{ id: 2, name: '用户B', status: '离线' },
{ id: 3, name: '用户C', status: '在线' }
],
total: 3
});
}, 1000);
});
}
}}
onClick={handleRefresh}
>
刷新数据
</FetchButton>
{data && (
<Alert
message={`当前数据:${data.users?.length} 个用户在线`}
type="info"
/>
)}
</Space>
</Card>
);
};
// beforeFetch 拦截
const BeforeFetchExample = () => {
const [allowed, setAllowed] = useState(true);
const handleFetch = ({ data }) => {
message.success('请求通过');
};
const beforeFetch = () => {
if (!allowed) {
message.warning('请求被 beforeFetch 拦截');
return false;
}
return true;
};
return (
<Space direction="vertical">
<Typography.Text type="secondary">beforeFetch 可以拦截请求</Typography.Text>
<Space>
<Button onClick={() => setAllowed(!allowed)} size="small">
{allowed ? '拦截请求' : '允许请求'}
</Button>
</Space>
<FetchButton
api={{
loader: async () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve({ data: '请求成功' });
}, 800);
});
}
}}
beforeFetch={beforeFetch}
onClick={handleFetch}
>
{allowed ? '发送请求' : '请求已拦截'}
</FetchButton>
</Space>
);
};
const BaseExample = () => {
return (
<Space direction="vertical" size="large">
<Typography.Title level={3}>FetchButton 请求按钮</Typography.Title>
<Typography.Paragraph>
FetchButton 集成了数据请求功能,基于 @kne/react-fetch 库实现。
自动管理加载状态,支持成功/失败回调、参数传递、请求拦截等功能。
</Typography.Paragraph>
<Flex vertical gap={32}>
<div>
<Typography.Title level={4}>基础用法</Typography.Title>
<BasicExample />
</div>
<div>
<Typography.Title level={4}>带参数请求</Typography.Title>
<WithParamsExample />
</div>
<div>
<Typography.Title level={4}>成功与失败回调</Typography.Title>
<CallbackExample />
</div>
<div>
<Typography.Title level={4}>文件导出场景</Typography.Title>
<ExportExample />
</div>
<div>
<Typography.Title level={4}>表单提交场景</Typography.Title>
<FormSubmitExample />
</div>
<div>
<Typography.Title level={4}>刷新数据场景</Typography.Title>
<RefreshExample />
</div>
<div>
<Typography.Title level={4}>请求拦截</Typography.Title>
<BeforeFetchExample />
</div>
</Flex>
</Space>
);
};
render(<BaseExample />);- ButtonFooter 底部按钮区
- ButtonFooter 是页面底部按钮区域组件,在小屏幕下自动将内容渲染到 body,方便表单页面的操作按钮布局。
- _ButtonGroup(@kne/current-lib_button-group)[import * as _ButtonGroup from "@kne/button-group"],(@kne/current-lib_button-group/dist/index.css),antd(antd)
const { ButtonFooter } = _ButtonGroup;
const { Flex, Button, Space, Typography, Card, Form, Input } = antd;
const { useState } = React;
// 基础用法
const BasicExample = () => {
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
ButtonFooter 固定在页面底部,在小屏幕(≤768px)下自动渲染到 body
</Typography.Text>
<Card
title="页面内容区域"
style={{ width: 400, minHeight: 200 }}
>
<Typography.Paragraph>
这是页面的主要内容区域。ButtonFooter 会自动计算高度并设置 CSS 变量,
方便页面布局调整。
</Typography.Paragraph>
<Typography.Paragraph>
在移动端,按钮会自动固定在屏幕底部,确保操作按钮始终可见。
</Typography.Paragraph>
</Card>
<ButtonFooter>
<Flex justify="flex-end" gap={8} style={{ padding: '16px 24px', background: '#fff', borderTop: '1px solid #f0f0f0' }}>
<Button>取消</Button>
<Button type="primary">保存</Button>
</Flex>
</ButtonFooter>
</Space>
);
};
// 表单提交场景
const FormExample = () => {
const [form] = Form.useForm();
const [loading, setLoading] = useState(false);
const handleSave = () => {
setLoading(true);
setTimeout(() => {
setLoading(false);
message.success('保存成功');
}, 1000);
};
const handleSubmit = () => {
setLoading(true);
setTimeout(() => {
setLoading(false);
message.success('提交成功');
}, 1000);
};
return (
<Card title="表单底部操作" style={{ width: 500 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
适用于表单页面的底部操作按钮
</Typography.Text>
<Form form={form} layout="vertical">
<Form.Item name="name" label="名称">
<Input placeholder="请输入名称" />
</Form.Item>
<Form.Item name="desc" label="描述">
<Input.TextArea placeholder="请输入描述" rows={4} />
</Form.Item>
</Form>
<ButtonFooter>
<Flex justify="flex-end" gap={8} style={{ padding: '16px 0', borderTop: '1px solid #f0f0f0' }}>
<Button onClick={() => form.resetFields()}>重置</Button>
<Button onClick={handleSave}>保存草稿</Button>
<Button type="primary" loading={loading} onClick={handleSubmit}>
提交
</Button>
</Flex>
</ButtonFooter>
</Space>
</Card>
);
};
// 居中对齐
const CenterExample = () => {
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">按钮居中对齐</Typography.Text>
<Card title="对话框" style={{ width: 400 }}>
<Typography.Paragraph>
这是对话框的内容区域,底部按钮居中对齐。
</Typography.Paragraph>
</Card>
<ButtonFooter>
<Flex justify="center" gap={8} style={{ padding: '16px 24px', background: '#fff', borderTop: '1px solid #f0f0f0' }}>
<Button>关闭</Button>
<Button type="primary">确认</Button>
</Flex>
</ButtonFooter>
</Space>
);
};
// 多按钮布局
const MultipleButtonsExample = () => {
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">多个操作按钮</Typography.Text>
<Card title="详情页面" style={{ width: 450 }}>
<Typography.Paragraph>
页面详情内容区域...
</Typography.Paragraph>
<Typography.Paragraph>
支持多个按钮布局,包括主要操作、次要操作等。
</Typography.Paragraph>
</Card>
<ButtonFooter>
<Flex justify="space-between" align="middle" style={{ padding: '12px 24px', background: '#fff', borderTop: '1px solid #f0f0f0' }}>
<Space>
<Button type="text" danger>删除</Button>
<Button type="text">导出</Button>
</Space>
<Space>
<Button>编辑</Button>
<Button type="primary">提交审核</Button>
</Space>
</Flex>
</ButtonFooter>
</Space>
);
};
// 紧凑样式
const CompactExample = () => {
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">紧凑样式</Typography.Text>
<Card title="设置页面" style={{ width: 400 }}>
<Typography.Paragraph>
系统设置内容区域...
</Typography.Paragraph>
</Card>
<ButtonFooter>
<Flex justify="flex-end" gap={8} style={{ padding: '8px 0', borderTop: '1px solid #f0f0f0' }}>
<Button size="small">取消</Button>
<Button size="small" type="primary">保存设置</Button>
</Flex>
</ButtonFooter>
</Space>
);
};
// 禁用状态
const DisabledExample = () => {
const [disabled, setDisabled] = useState(true);
return (
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">按钮禁用状态</Typography.Text>
<Space>
<Button onClick={() => setDisabled(!disabled)} size="small">
{disabled ? '启用按钮' : '禁用按钮'}
</Button>
</Space>
<Card title="详情页" style={{ width: 400 }}>
<Typography.Paragraph>
内容区域...
</Typography.Paragraph>
</Card>
<ButtonFooter>
<Flex justify="flex-end" gap={8} style={{ padding: '16px 0', borderTop: '1px solid #f0f0f0' }}>
<Button disabled={disabled}>编辑</Button>
<Button type="primary" disabled={disabled}>
提交
</Button>
</Flex>
</ButtonFooter>
</Space>
);
};
// 步骤条场景
const StepsExample = () => {
const [currentStep, setCurrentStep] = useState(0);
const totalSteps = 3;
const nextStep = () => {
if (currentStep < totalSteps - 1) {
setCurrentStep(currentStep + 1);
}
};
const prevStep = () => {
if (currentStep > 0) {
setCurrentStep(currentStep - 1);
}
};
const stepContent = [
'第一步:填写基本信息',
'第二步:上传相关文件',
'第三步:确认提交信息'
];
return (
<Card title="步骤操作" style={{ width: 450 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
当前步骤:{currentStep + 1} / {totalSteps}
</Typography.Text>
<div style={{ padding: '24px', background: '#f5f5f5', borderRadius: '8px', minHeight: '100px' }}>
<Typography.Text>{stepContent[currentStep]}</Typography.Text>
</div>
<ButtonFooter>
<Flex justify="space-between" style={{ padding: '16px 0', borderTop: '1px solid #f0f0f0' }}>
<Button disabled={currentStep === 0} onClick={prevStep}>
上一步
</Button>
<Button
type="primary"
onClick={currentStep === totalSteps - 1 ? () => message.success('提交成功') : nextStep}
>
{currentStep === totalSteps - 1 ? '提交' : '下一步'}
</Button>
</Flex>
</ButtonFooter>
</Space>
</Card>
);
};
// 实际应用场景 - 完整页面
const FullPageExample = () => {
const [form] = Form.useForm();
const handleSubmit = () => {
message.success('提交成功');
};
const handleSave = () => {
message.success('已保存草稿');
};
return (
<Card title="完整页面示例" style={{ width: 500 }}>
<Space direction="vertical" style={{ width: '100%' }}>
<Typography.Text type="secondary">
模拟一个完整的表单页面,包含标题、内容区和底部操作按钮
</Typography.Text>
<div style={{ minHeight: '200px', padding: '20px', background: '#fafafa', borderRadius: '8px' }}>
<Typography.Title level={5}>用户信息编辑</Typography.Title>
<Form form={form} layout="vertical">
<Form.Item name="username" label="用户名">
<Input placeholder="请输入用户名" />
</Form.Item>
<Form.Item name="email" label="邮箱">
<Input placeholder="请输入邮箱" />
</Form.Item>
</Form>
</div>
<ButtonFooter>
<Flex justify="flex-end" gap={12} style={{ padding: '16px 24px', background: '#fff', borderTop: '1px solid #f0f0f0' }}>
<Button onClick={() => form.resetFields()}>重置</Button>
<Button onClick={handleSave}>保存草稿</Button>
<Button type="primary" onClick={handleSubmit}>提交</Button>
</Flex>
</ButtonFooter>
</Space>
</Card>
);
};
const BaseExample = () => {
return (
<Space direction="vertical" size="large">
<Typography.Title level={3}>ButtonFooter 底部按钮区</Typography.Title>
<Typography.Paragraph>
ButtonFooter 是页面底部按钮区域组件,可以自动计算高度并设置 CSS 变量。
在小屏幕(≤768px)下,会将内容渲染到 body,确保按钮始终可见。
适用于表单页面、详情页面、对话框等场景。
</Typography.Paragraph>
<Flex vertical gap={32}>
<div>
<Typography.Title level={4}>基础用法</Typography.Title>
<BasicExample />
</div>
<div>
<Typography.Title level={4}>表单提交场景</Typography.Title>
<FormExample />
</div>
<div>
<Typography.Title level={4}>居中对齐</Typography.Title>
<CenterExample />
</div>
<div>
<Typography.Title level={4}>多按钮布局</Typography.Title>
<MultipleButtonsExample />
</div>
<div>
<Typography.Title level={4}>紧凑样式</Typography.Title>
<CompactExample />
</div>
<div>
<Typography.Title level={4}>禁用状态</Typography.Title>
<DisabledExample />
</div>
<div>
<Typography.Title level={4}>步骤操作</Typography.Title>
<StepsExample />
</div>
<div>
<Typography.Title level={4}>完整页面示例</Typography.Title>
<FullPageExample />
</div>
</Flex>
</Space>
);
};
render(<BaseExample />);自适应按钮组组件,能够根据容器宽度自动调整显示的按钮数量,并将多余的按钮放入下拉菜单中。
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| list | Array<object | function> | [] | 按钮列表,可以是配置对象或渲染函数 |
| compact | boolean | false | 是否使用紧凑模式(Space.Compact) |
| showLength | number | - | 指定显示的按钮数量,不指定则自动计算 |
| more | ReactNode | - | 自定义"更多"按钮 |
| moreType | 'default' | 'link' | 'default' | 更多按钮类型 |
| getPopupContainer | function | - | 下拉菜单渲染父节点 |
| trigger | string | - | 下拉菜单触发方式 |
| itemClassName | string | - | 按钮项的自定义类名 |
| ...SpaceProps | - | - | Space 组件的其他属性(size、split、align、style等) |
当 list 项为对象时,支持以下属性:
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | ReactNode | - | 按钮内容 |
| type | string | - | 按钮类型(primary、default、dashed、link、text) |
| disabled | boolean | false | 是否禁用 |
| hidden | boolean | false | 是否隐藏 |
| confirm | boolean | false | 是否需要确认 |
| message | string | ReactNode | - | 确认提示内容(设置后会自动使用 ConfirmButton) |
| isDelete | boolean | false | 是否为删除操作(红色按钮) |
| isModal | boolean | false | 是否使用模态框确认(在下拉菜单中自动启用) |
| buttonComponent | ReactComponent | - | 自定义按钮组件 |
| tooltipProps | object | - | Tooltip 组件属性(禁用时显示提示) |
| ...ButtonProps | - | - | Button 组件的其他属性 |
当 list 项为函数时,函数签名为:
(props: { key: number; className: string }, context: { isDropdown: boolean }) => ReactNode封装了加载状态的按钮组件,简化异步操作的处理。
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| onClick | function | Promise | - | 点击按钮时的回调函数,可以返回 Promise |
| loading | boolean | false | 是否显示加载状态 |
| disabled | boolean | false | 是否禁用按钮 |
| children | ReactNode | function | - | 按钮内容,可以是函数接收 loading 状态 |
| ...ButtonProps | - | - | Button 组件的其他属性 |
用于管理异步操作加载状态的 Hook。
| 参数名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| callback | function | - | 异步回调函数 |
| 名称 | 类型 | 说明 |
|---|---|---|
| isLoading | boolean | 当前加载状态 |
| setIsLoading | function | 设置加载状态的函数 |
| callback | function | 包装后的回调函数 |
带有确认功能的按钮组件,支持弹窗确认和模态框确认两种模式。
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | ReactNode | - | 按钮内容 |
| onClick | function | Promise | - | 确认后的回调函数,可以返回 Promise |
| title | string | ReactNode | - | 确认框标题 |
| message | string | ReactNode | - | 确认框内容 |
| okText | string | - | 确认按钮文字(默认根据 isDelete 动态显示) |
| cancelText | string | - | 取消按钮文字 |
| isModal | boolean | false | 是否使用模态框确认(默认为 Popconfirm) |
| isDelete | boolean | true | 是否为删除操作(红色按钮、确认按钮) |
| showCancel | boolean | true | 是否显示取消按钮 |
| placement | string | - | Popconfirm 的位置 |
| getContainer | function | - | 确认框渲染容器 |
| renderModal | function | - | 自定义 Modal 渲染函数 |
| onCancel | function | - | 取消按钮的回调 |
| ...ButtonProps | - | - | Button 组件的其他属性 |
ConfirmButton 的链接样式变体。
ConfirmButton 的纯文本样式变体。
高阶组件,用于为任意组件添加确认功能。
⚠️ 该 API 已标记为废弃,后续版本可能删除,建议不要使用。
集成了数据请求功能的按钮组件,基于 @kne/react-fetch 库实现。
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| api | object | function | - | 请求 API 配置 |
| params | object | - | 请求参数 |
| onSuccess | function | - | 请求成功回调,参数为 { data } |
| onError | function | - | 请求失败回调 |
| beforeFetch | function | - | 请求前处理函数,返回 false 可阻止请求 |
| afterFetch | function | - | 请求后处理函数 |
| fetchOptions | object | - | 传递给 fetch 函数的选项 |
| onClick | function | - | 请求成功后的回调(与 onSuccess 相同) |
| ...LoadingButtonProps | - | - | LoadingButton 组件的其他属性 |
api 可以是对象或函数:
// 对象形式
api: {
loader: async ({ params }) => {
return { data: 'response data' };
}
}
// 函数形式
api: async ({ params }) => {
return { data: 'response data' };
}页面底部按钮区域组件,可以自动计算高度并设置 CSS 变量。
| 属性名 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| children | ReactNode | - | 按钮区域内容 |
| className | string | - | 容器的自定义类名 |
| innerClassName | string | - | 内部容器的自定义类名 |
| target | HTMLElement | document.body | 移动端渲染的目标容器 |
- 在小屏幕(≤768px)下,会将内容使用 Portal 渲染到 body
- 自动计算高度并设置 CSS 变量
- 适用于固定在页面底部的操作按钮区域