knight-ui
v1.1.3
Published
基于React的Knight-ui前端UI组件库
Maintainers
Readme
Knight-UI
基于 React 18+ 的企业级前端 UI 组件库,提供 80+ 高质量组件。
目录
安装
npm install knight-ui快速开始
import React from "react";
import { createRoot } from "react-dom/client";
import { Button, ConfigProvider } from "knight-ui";
const App = () => (
<ConfigProvider componentSize="default">
<Button type="primary" onClick={() => alert("Hello Knight-UI")}>
点击按钮
</Button>
</ConfigProvider>
);
createRoot(document.getElementById("root")!).render(<App />);同时引入样式 Token(CSS 变量):
import "knight-ui/tokens.css";主题定制
Knight-UI 通过 CSS 自定义属性(CSS Variables)实现主题系统。在 <html> 上设置 data-ku-theme 属性切换暗亮模式:
<html data-ku-theme="dark"><!-- 暗色模式 --></html>
<html data-ku-theme="light"><!-- 亮色模式 --></html>常用 Token 变量:
| 变量名 | 说明 |
|---|---|
| --ku-color-primary | 主色 |
| --ku-color-text-0 | 主要文本色 |
| --ku-color-text-1 | 次要文本色 |
| --ku-color-bg-0 | 主背景色 |
| --ku-color-bg-1 | 次背景色 |
| --ku-color-bg-2 | 三级背景色 |
| --ku-color-border | 边框色 |
| --ku-font-family | 全局字体 |
通用 Props(UIProps)
所有组件继承以下通用属性:
| 属性 | 类型 | 说明 |
|---|---|---|
| style | React.CSSProperties | 内联样式 |
| className | string | 自定义类名 |
| disabled | boolean | 是否禁用 |
| visible | boolean | 是否可见 |
| id | string | DOM id |
| theme | string | 主题变体 |
| cssVars | Record<string, string> | CSS 变量覆盖 |
Basic 基础
Button 按钮
import { Button } from "knight-ui";
// 基础用法
<Button type="primary" onClick={() => console.log("clicked")}>主要按钮</Button>
<Button type="secondary">次要按钮</Button>
<Button type="danger">危险按钮</Button>
// 带图标 + 加载
<Button type="primary" icon={<IconSearch />} loading>搜索中</Button>
// 按钮组
<Button.Group>
<Button type="secondary" theme="light">左</Button>
<Button type="primary" theme="light">中</Button>
<Button type="secondary" theme="light">右</Button>
</Button.Group>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "primary" \| "secondary" \| "tertiary" \| "warning" \| "danger" | "primary" | 按钮类型 |
| theme | "solid" \| "borderless" \| "light" | "solid" | 按钮主题 |
| size | "small" \| "default" \| "large" | "default" | 按钮尺寸 |
| shape | "circle" \| "round" | — | 按钮形状 |
| icon | React.ReactNode | — | 图标 |
| iconPosition | "left" \| "right" | "left" | 图标位置 |
| loading | boolean | false | 加载中 |
| block | boolean | false | 通栏 100% 宽度 |
| htmlType | "button" \| "submit" \| "reset" | "button" | 原生 type |
| onClick | (e: MouseEvent) => void | — | 点击回调 |
FloatButton 悬浮按钮
import { FloatButton } from "knight-ui";
<FloatButton icon={<IconPlus />} size={40} onClick={() => console.log("clicked")} />
// 按钮组
<FloatButton.Group icon={<IconPlus />} size={40} direction="vertical">
<IconEdit />
<IconStar />
<IconSetting />
</FloatButton.Group>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| icon | React.ReactNode | — | 图标 |
| size | number | — | 尺寸(px) |
| position | { right?, bottom?, left?, top? } | — | 定位偏移 |
| onClick | (e: MouseEvent) => void | — | 点击回调 |
FloatButton.Group 额外支持 direction: "vertical" | "horizontal"。
Icon 图标
import { Icon, IconStar, IconDelete, IconRefresh } from "knight-ui";
// 通用 Icon 组件
<Icon type="IconStar" size="large" color="#f59e0b" />
// 独立组件(推荐,支持 tree-shaking)
<IconStar size="large" color="#f59e0b" />
<IconDelete size="large" color="#ef4444" onClick={() => console.log("delete")} />
<IconRefresh spin size="large" />
<IconArrowRight rotate={90} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | IconType | — | 图标类型(200+) |
| size | "extraSmall" \| "small" \| "default" \| "large" \| "extraLarge" | "default" | 尺寸 |
| color | string | — | 颜色 |
| spin | boolean | false | 旋转动画 |
| rotate | number | — | 固定旋转角度 |
| onClick | (e: MouseEvent) => void | — | 点击回调 |
Typography 排版
import { Title, Text, Paragraph } from "knight-ui";
<Title heading={1}>H1 标题</Title>
<Text type="secondary" strong>加粗次要文本</Text>
<Text mark>高亮文本</Text>
<Text code>const x = 1;</Text>
<Text delete>已删除文本</Text>
<Text ellipsis>超长文本溢出省略...</Text>
<Paragraph spacing="extended">
段落内容,spacing 控制段落间距。
</Paragraph>Title:heading: 1-6、ellipsis
Text:type("primary" | "secondary" | "tertiary" | "quaternary" | "warning" | "danger" | "success")、strong、underline、delete、mark、code、ellipsis
Paragraph:spacing: "normal" | "extended"、ellipsis
Divider 分割线
import { Divider } from "knight-ui";
// 水平
<Divider />
<Divider align="left">左侧文字</Divider>
<Divider dashed />
<Divider color="#a78bfa" margin={24}>紫色分割线</Divider>
// 垂直
<div style={{ display: "flex", alignItems: "center", height: 60 }}>
<Text>左</Text>
<Divider layout="vertical" />
<Text>右</Text>
</div>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| layout | "horizontal" \| "vertical" | "horizontal" | 方向 |
| dashed | boolean | false | 虚线 |
| align | "left" \| "center" \| "right" | "center" | 文字对齐 |
| margin | string \| number | — | 间距 |
| color | string | — | 颜色 |
Space 间距
import { Space, Button } from "knight-ui";
// 水平排列
<Space spacing="medium">
<Button>A</Button>
<Button>B</Button>
<Button>C</Button>
</Space>
// 垂直 + 自动换行
<Space vertical spacing={16} wrap align="start">
<Button>第一行</Button>
<Button>第二行</Button>
</Space>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| spacing | "tight" \| "medium" \| "loose" \| "extraLoose" \| number | "medium" | 间距 |
| align | "start" \| "center" \| "end" \| "baseline" | "center" | 对齐方式 |
| vertical | boolean | false | 垂直排列 |
| wrap | boolean | false | 自动换行 |
Layout 布局
import { Layout, Text } from "knight-ui";
<Layout style={{ height: 400 }}>
<Layout.Header style={{ padding: 16, background: "#1e1e2e" }}>
<Text strong>Header</Text>
</Layout.Header>
<div style={{ display: "flex", flex: 1 }}>
<Layout.Sider width={200} style={{ background: "#16162a", padding: 16 }}>
<Text>Sider</Text>
</Layout.Sider>
<Layout.Content style={{ padding: 16 }}>
<Text>Content</Text>
</Layout.Content>
</div>
<Layout.Footer style={{ padding: 8, background: "#1e1e2e", textAlign: "center" }}>
<Text>Footer</Text>
</Layout.Footer>
</Layout>子组件:Layout.Header、Layout.Sider、Layout.Content、Layout.Footer
Layout.Sider:width、collapsedWidth、defaultCollapsed、trigger
Grid 栅格
import { Row, Col } from "knight-ui";
<Row gutter={16} justify="center">
<Col span={8}><div>col-8</div></Col>
<Col span={8}><div>col-8</div></Col>
<Col span={8}><div>col-8</div></Col>
</Row>
<Row gutter={[16, 24]}>
<Col span={12} offset={6}><div>col-12 offset-6</div></Col>
</Row>Row:gutter、justify("start" | "end" | "center" | "space-around" | "space-between")、align("top" | "middle" | "bottom")
Col:span(24 等分)、offset、xs/sm/md/lg/xl/xxl
Resizable 可调整尺寸
import { Resizable } from "knight-ui";
<Resizable
defaultWidth={400}
defaultHeight={300}
minWidth={200}
minHeight={150}
maxWidth={800}
maxHeight={600}
onResize={(w, h) => console.log(w, h)}
>
<div>拖拽边缘或角落调整尺寸</div>
</Resizable>
// 仅右侧可拖拽
<Resizable defaultWidth={300} resizeEdge={["right"]} minWidth={150}>
<div>拖拽右边缘</div>
</Resizable>
// 等比缩放
<Resizable defaultWidth={400} defaultHeight={300} lockAspectRatio>
<div>锁定宽高比</div>
</Resizable>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| defaultWidth / defaultHeight | number | — | 默认尺寸 |
| minWidth / minHeight | number | — | 最小尺寸 |
| maxWidth / maxHeight | number | — | 最大尺寸 |
| resizeEdge | ResizeEdge[] | 全部 | 可拖拽边缘 |
| lockAspectRatio | boolean | false | 锁定宽高比 |
| onResize | (w, h) => void | — | 尺寸变化回调 |
Input 输入
Input 输入框
import { Input } from "knight-ui";
// 非受控(浏览器原生管理输入,IME 无干扰)
<Input placeholder="请输入" onChange={(v) => console.log(v)} />
<Input showClear defaultValue="可清除" />
// 受控(通过 value 管理显示值,Form.Field 自动使用此模式)
<Input value={text} onChange={(v) => setText(v)} placeholder="受控输入" />
<Input prefix={<IconSearch />} placeholder="搜索" />
<Input addonBefore="https://" addonAfter=".com" placeholder="域名" />
<Input type="password" placeholder="密码" />
<Input size="large" placeholder="大尺寸" />
// 多行文本(同样支持 value / defaultValue)
<Input.TextArea rows={4} placeholder="多行文本" onChange={(v) => console.log(v)} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value | string | — | 受控值(提供后组件变为受控模式) |
| defaultValue | string | — | 非受控默认值 |
| type | "text" \| "password" | "text" | 输入类型 |
| placeholder | string | — | 占位符 |
| size | "small" \| "default" \| "large" | "default" | 尺寸 |
| prefix / suffix | React.ReactNode | — | 前/后缀图标 |
| addonBefore / addonAfter | React.ReactNode | — | 前/后置标签 |
| showClear | boolean | false | 清除按钮 |
| validateStatus | "warning" \| "error" \| "success" | — | 校验状态 |
| onChange | (value: string) => void | — | 变更回调 |
InputNumber 数字输入
import { InputNumber } from "knight-ui";
<InputNumber defaultValue={50} min={0} max={100} onChange={(v) => console.log(v)} />
<InputNumber defaultValue={10} step={0.1} min={0} max={1} />
<InputNumber prefix="¥" defaultValue={99} />
<InputNumber suffix="px" defaultValue={16} />
<InputNumber defaultValue={50} innerButtons />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| min / max | number | — | 最小/最大值 |
| step | number | 1 | 步长 |
| innerButtons | boolean | false | 内部步进按钮 |
| hideButtons | boolean | false | 隐藏步进按钮 |
| onChange | (value: number) => void | — | 变更回调 |
Select 选择器
import { Select } from "knight-ui";
const options = [
{ label: "选项一", value: "1" },
{ label: "选项二", value: "2" },
{ label: "选项三", value: "3" },
];
<Select optionList={options} defaultValue="1" onChange={(v) => console.log(v)} />
<Select optionList={options} multiple defaultValue={["1", "2"]} max={3} />
<Select optionList={options} filter placeholder="搜索选择" />
<Select optionList={options} loading />
// 设置下拉可见选项数量(按每项约 30px 推算下拉高度,超出滚动)
<Select optionList={options} dropdownVisibleCount={6} />子组件:Select.Option、Select.OptGroup
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| optionList | SelectOption[] | — | 选项列表 |
| multiple | boolean | false | 多选 |
| filter | boolean | false | 可搜索 |
| max | number | — | 多选最大数量 |
| maxTagCount | number | — | 最多显示标签数 |
| dropdownVisibleCount | number | — | 下拉可见选项数量(按每项约 30px 推算高度,默认 200px) |
| onChange | (value) => void | — | 变更回调 |
Cascader 级联选择
import { Cascader } from "knight-ui";
const treeData = [
{
label: "浙江", value: "zj",
children: [
{ label: "杭州", value: "hz" },
{ label: "宁波", value: "nb" },
],
},
{ label: "江苏", value: "js", children: [{ label: "南京", value: "nj" }] },
];
<Cascader treeData={treeData} onChange={(v) => console.log(v)} />
<Cascader treeData={treeData} multiple filter placeholder="搜索" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| treeData | CascaderOption[] | — | 级联数据 |
| multiple | boolean | false | 多选 |
| filter | boolean | false | 可搜索 |
| changeOnSelect | boolean | false | 任意选中即改变 |
| onChange | (value: string[]) => void | — | 变更回调 |
DatePicker 日期选择
import { DatePicker } from "knight-ui";
<DatePicker onChange={(date, dateStr) => console.log(date, dateStr)} />
<DatePicker type="dateRange" defaultValue={[new Date(), new Date()]} />
<DatePicker type="dateTime" showClear />
<DatePicker format="yyyy-MM-dd" presets={[{ label: "今天", value: new Date() }]} />
<DatePicker disabledDate={(d) => d.getTime() < Date.now()} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "date" \| "dateRange" \| "dateTime" \| "dateTimeRange" \| "month" | "date" | 类型 |
| format | string | — | 显示格式 |
| presets | DatePickerPreset[] | — | 预设快捷选项 |
| disabledDate | (date: Date) => boolean | — | 禁用日期 |
| onChange | (date, dateString) => void | — | 变更回调 |
TimePicker 时间选择
import { TimePicker } from "knight-ui";
<TimePicker onChange={(v) => console.log(v)} />
<TimePicker format="HH:mm:ss" defaultValue="14:30:00" />
<TimePicker hourStep={2} minuteStep={15} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value / defaultValue | string | — | 值(HH:mm 或 HH:mm:ss) |
| format | "HH:mm" \| "HH:mm:ss" | "HH:mm" | 格式 |
| hourStep / minuteStep / secondStep | number | 1 | 步长 |
| onChange | (value: string) => void | — | 变更回调 |
Checkbox 复选框
import { Checkbox } from "knight-ui";
// 单个
<Checkbox defaultChecked onChange={(checked) => console.log(checked)}>同意协议</Checkbox>
<Checkbox indeterminate>半选状态</Checkbox>
// 组合
<Checkbox.Group defaultValue={["a", "c"]} onChange={(v) => console.log(v)}>
<Checkbox value="a">选项 A</Checkbox>
<Checkbox value="b">选项 B</Checkbox>
<Checkbox value="c">选项 C</Checkbox>
</Checkbox.Group>
// 垂直排列
<Checkbox.Group direction="vertical" disabled>
<Checkbox value="1">禁用的选项</Checkbox>
</Checkbox.Group>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| checked / defaultChecked | boolean | — | 选中状态 |
| indeterminate | boolean | false | 半选状态 |
| onChange | (checked: boolean) => void | — | 变更回调 |
Checkbox.Group:value/defaultValue、direction、disabled、onChange
Radio 单选框
import { Radio } from "knight-ui";
<Radio.Group defaultValue="b" onChange={(v) => console.log(v)}>
<Radio value="a">选项 A</Radio>
<Radio value="b">选项 B</Radio>
<Radio value="c">选项 C</Radio>
</Radio.Group>
// 按钮样式
<Radio.Group type="button" defaultValue="a">
<Radio value="a">A</Radio>
<Radio value="b">B</Radio>
</Radio.Group>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| checked | boolean | — | 选中状态 |
| type | "default" \| "button" \| "card" | "default" | 样式类型 |
Radio.Group:value/defaultValue、direction、type、disabled、onChange
Switch 开关
import { Switch } from "knight-ui";
<Switch defaultChecked onChange={(v) => console.log(v)} />
<Switch checkedText="开" uncheckedText="关" defaultChecked />
<Switch size="large" loading />
<Switch disabled />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| checked / defaultChecked | boolean | — | 开关状态 |
| size | "small" \| "default" \| "large" | "default" | 尺寸 |
| loading | boolean | false | 加载中 |
| checkedText / uncheckedText | React.ReactNode | — | 开关文字 |
| onChange | (checked: boolean) => void | — | 变更回调 |
Slider 滑块
import { Slider } from "knight-ui";
<Slider defaultValue={30} onChange={(v) => console.log(v)} />
// 范围滑块
<Slider range defaultValue={[20, 60]} showMinMax />
// 带刻度
<Slider defaultValue={50} step={10} tooltipVisible showMinMax />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value / defaultValue | number \| [number, number] | — | 值 |
| min / max | number | 0 / 100 | 范围 |
| step | number | 1 | 步长 |
| range | boolean | false | 范围选择 |
| tooltipVisible | boolean | false | 显示提示 |
| showMinMax | boolean | false | 显示最值标签 |
| marks | Record<number, string> | — | 刻度标记 |
| onChange | (value) => void | — | 变更回调 |
Rating 评分
import { Rating } from "knight-ui";
<Rating defaultValue={3} onChange={(v) => console.log(v)} />
<Rating defaultValue={3.5} allowHalf />
<Rating defaultValue={7} count={10} />
<Rating size="large" disabled defaultValue={4} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| count | number | 5 | 星星数量 |
| allowHalf | boolean | false | 允许半星 |
| size | "small" \| "default" \| "large" | "default" | 尺寸 |
| character | React.ReactNode | — | 自定义图标 |
| tooltips | string[] | — | 提示文字 |
| onChange | (value: number) => void | — | 变更回调 |
TagInput 标签输入
import { TagInput } from "knight-ui";
<TagInput defaultValue={["React", "TypeScript"]} onChange={(v) => console.log(v)} />
<TagInput placeholder="按回车添加" max={5} maxTagCount={3} />
<TagInput separator="," placeholder="逗号分隔" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value / defaultValue | string[] | — | 标签列表 |
| max | number | — | 最大标签数 |
| maxTagCount | number | — | 最多显示数 |
| separator | string | — | 分隔符 |
| onChange | (value: string[]) => void | — | 变更回调 |
ColorPicker 颜色选择器
import { ColorPicker } from "knight-ui";
<ColorPicker defaultValue="#8b5cf6" onChange={(v) => console.log(v)} />
<ColorPicker alpha defaultFormat="rgba" />
<ColorPicker eyeDropper />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value / defaultValue | ColorValue | — | 颜色值 |
| defaultFormat | "hex" \| "rgba" \| "hsva" | "hex" | 格式 |
| alpha | boolean | false | 透明度通道 |
| eyeDropper | boolean | false | 取色器 |
| onChange | (value: ColorValue) => void | — | 变更回调 |
Upload 上传
import { Upload, Button } from "knight-ui";
<Upload action="/api/upload" accept=".jpg,.png" onChange={(files) => console.log(files)}>
<Button type="primary">上传文件</Button>
</Upload>
<Upload listType="pictureCard" limit={3} multiple>
<span>+ 上传图片</span>
</Upload>
<Upload
customRequest={async (options) => {
const formData = new FormData();
formData.append("file", options.file);
await fetch("/api/upload", { method: "POST", body: formData });
options.onSuccess();
}}
>
<Button>自定义上传</Button>
</Upload>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| action | string | — | 上传地址 |
| accept | string | — | 文件类型 |
| listType | "picture" \| "list" \| "pictureCard" | "list" | 列表类型 |
| limit | number | — | 最大数量 |
| multiple | boolean | false | 多文件 |
| beforeUpload | (file) => boolean | — | 上传前校验 |
| customRequest | (options) => Promise<void> | — | 自定义上传 |
| onChange | (fileList) => void | — | 变更回调 |
AutoComplete 自动完成
import { AutoComplete } from "knight-ui";
const data = ["Apple", "Banana", "Orange", "Grape"];
<AutoComplete data={data} onSelect={(opt) => console.log(opt)} />
<AutoComplete
data={data}
filter
onSearch={(keyword) => console.log(keyword)}
placeholder="输入搜索"
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| data | (string \| AutoCompleteOption)[] | — | 数据源 |
| filter | boolean | — | 本地过滤 |
| onSearch | (inputValue) => void | — | 搜索回调 |
| onSelect | (option) => void | — | 选中回调 |
Transfer 穿梭框
import { Transfer } from "knight-ui";
const data = [
{ key: "1", title: "选项一" },
{ key: "2", title: "选项二" },
{ key: "3", title: "选项三" },
];
<Transfer dataSource={data} defaultValue={["1"]} titles={["待选", "已选"]} onChange={(keys) => console.log(keys)} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| dataSource | TransferItem[] | — | 数据源 |
| titles | [string, string] | — | 左右标题 |
| filter | boolean | — | 可搜索 |
| onChange | (targetKeys: string[]) => void | — | 变更回调 |
TreeSelect 树选择
import { TreeSelect } from "knight-ui";
const treeData = [
{ label: "Node 1", value: "1", children: [{ label: "Node 1-1", value: "1-1" }] },
{ label: "Node 2", value: "2" },
];
<TreeSelect treeData={treeData} onChange={(v) => console.log(v)} />
<TreeSelect treeData={treeData} multiple filter placeholder="搜索" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| treeData | TreeSelectNode[] | — | 树数据 |
| multiple | boolean | false | 多选 |
| filter | boolean | false | 可搜索 |
| onChange | (value) => void | — | 变更回调 |
PinCode 验证码输入
import { PinCode } from "knight-ui";
<PinCode count={6} onComplete={(v) => console.log("complete:", v)} />
<PinCode count={4} format="number" autoFocus size="large" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| count | number | — | 位数 |
| format | "number" \| "mixed" \| RegExp | — | 字符格式 |
| autoFocus | boolean | false | 自动聚焦 |
| onComplete | (value: string) => void | — | 输入完成回调 |
Form 表单
import { Form, Input, Button } from "knight-ui";
// 基础用法
<Form
layout="horizontal"
labelWidth={100}
onSubmit={(values) => console.log(values)}
onSubmitFail={(values) => console.log(values)}
getFormApi={(api) => (window.formApi = api)}
>
<Form.Field field="name" label="姓名" rules={[{ required: true, message: "请输入姓名" }]}>
<Input placeholder="请输入姓名" />
</Form.Field>
<Form.Field field="email" label="邮箱"
rules={[{ required: true, message: "请输入邮箱" }, { pattern: /^\S+@\S+$/, message: "邮箱格式不正确" }]}>
<Input placeholder="请输入邮箱" />
</Form.Field>
<Button type="primary" htmlType="submit">提交</Button>
</Form>
// 动态字段(通过 FormApi 控制)
const formApiRef = useRef<FormApi>(null);
<Form getFormApi={(api) => (formApiRef.current = api)}>
<Form.Field field="name" label="名称"><Input /></Form.Field>
</Form>
// 动态添加/移除字段
formApiRef.current?.addField("dynamic_key", { label: "动态字段", value: "默认值" });
formApiRef.current?.removeField("dynamic_key");
// 程序化读写
formApiRef.current?.setFieldValue("name", "新值");
formApiRef.current?.setFieldsValue({ name: "A", email: "B" });
const allValues = formApiRef.current?.getValues();
const singleValue = formApiRef.current?.getFieldValue("name");
// 手动校验
const validValues = await formApiRef.current?.validate(); // 通过返回 values,失败返回 null
formApiRef.current?.reset(); // 重置所有字段| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| layout | "horizontal" \| "vertical" | "vertical" | 布局 |
| labelPosition | "left" \| "top" | "top" | 标签位置 |
| labelAlign | "left" \| "right" \| "center" | "left" | 标签对齐 |
| labelWidth | number | 80 | 标签宽度 |
| getFormApi | (api: FormApi) => void | — | 获取表单 API |
| onSubmit | (values) => void | — | 校验通过后回调 |
| onSubmitFail | (values) => void | — | 校验失败回调 |
FormApi 方法:
| 方法 | 说明 |
|---|---|
| getValues() | 获取所有字段值 |
| setValues(values) | 批量设置字段值(合并) |
| getFieldValue(field) | 获取单个字段值 |
| setFieldValue(field, value) | 设置单个字段值 |
| setFieldsValue(values) | 批量设置(仅更新已注册字段) |
| addField(field, meta?) | 动态添加字段(已存在则更新) |
| removeField(field) | 动态移除字段 |
| validate() | 手动校验,通过返回 values,失败返回 null |
| reset() | 重置所有字段值为空 |
| setError(field, error) | 设置字段错误信息 |
Form.Field:field、label、rules?: FormRule[]、value?: any
FormRule:
| 属性 | 类型 | 说明 |
|---|---|---|
| required | boolean | 必填 |
| message | string | 错误提示 |
| min / max | number | 数值范围 |
| minLength / maxLength | number | 字符长度范围 |
| pattern | RegExp | 正则校验 |
| validator | (value, values) => string \| null \| Promise<string \| null> | 自定义校验 |
Navigation 导航
Navigation 导航菜单
import { Navigation } from "knight-ui";
import { IconStar, IconInfoCircle, IconSetting } from "knight-ui";
const items = [
{ key: "home", label: "首页", icon: <IconStar size="extraSmall" /> },
{
key: "docs", label: "文档", icon: <IconInfoCircle size="extraSmall" />,
children: [
{ key: "guide", label: "快速开始" },
{ key: "api", label: "API 参考" },
],
},
{ key: "about", label: "关于", icon: <IconSetting size="extraSmall" /> },
];
// 垂直模式 + 折叠切换
const [collapsed, setCollapsed] = useState(false);
<Navigation items={items} mode="vertical" isCollapsed={collapsed} onCollapseChange={setCollapsed}
defaultSelectedKeys={["home"]} onSelect={(k) => console.log(k)} />
// 水平模式
<Navigation items={items} mode="horizontal" trigger="click" />NavItem:key、label、icon?: React.ReactNode、disabled?: boolean、children?: NavItem[]
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items | NavItem[] | — | 菜单项 |
| mode | "horizontal" \| "vertical" | "vertical" | 排列模式 |
| trigger | "hover" \| "click" | "hover" | 子菜单触发方式 |
| isCollapsed | boolean | — | 折叠状态(受控) |
| defaultIsCollapsed | boolean | false | 默认折叠状态 |
| onCollapseChange | (isCollapsed: boolean) => void | — | 折叠切换回调 |
| selectedKeys / defaultSelectedKeys | string[] | — | 当前选中 |
| openKeys / defaultOpenKeys | string[] | — | 当前展开的子菜单 |
| multiple | boolean | false | 是否多选 |
| onSelect | (key: string) => void | — | 选中回调 |
| onOpenChange | (openKeys: string[]) => void | — | 展开变化回调 |
Tabs 标签页
import { Tabs } from "knight-ui";
const items = [
{ key: "a", label: "标签 A", content: <div>内容 A</div> },
{ key: "b", label: "标签 B", content: <div>内容 B</div> },
{ key: "c", label: "标签 C", content: <div>内容 C</div>, closable: true },
];
<Tabs items={items} defaultActiveKey="a" onChange={(k) => console.log(k)} />
<Tabs items={items} type="card" />
<Tabs items={items} type="button" />
<Tabs items={items} collapsible addable onTabClose={(k) => console.log("close", k)} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items | TabItem[] | — | 标签项 |
| activeKey / defaultActiveKey | string | — | 当前选中 |
| type | "line" \| "card" \| "button" | "line" | 样式类型 |
| tabPosition | "top" \| "left" \| "right" \| "bottom" | "top" | 位置 |
| collapsible | boolean | false | 折叠模式 |
| addable | boolean | false | 可新增标签 |
| onChange | (key: string) => void | — | 切换回调 |
| onTabClose | (key: string) => void | — | 关闭回调 |
Tree 树
import { Tree } from "knight-ui";
const treeData = [
{
key: "1", title: "节点 1",
children: [
{ key: "1-1", title: "节点 1-1" },
{ key: "1-2", title: "节点 1-2" },
],
},
{ key: "2", title: "节点 2" },
];
<Tree treeData={treeData} defaultExpandAll onSelect={(keys) => console.log(keys)} />
<Tree treeData={treeData} checkable onCheck={(keys) => console.log(keys)} />
<Tree treeData={treeData} multiple />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| treeData | TreeNodeData[] | — | 树数据 |
| checkable | boolean | false | 可复选 |
| multiple | boolean | false | 多选 |
| defaultExpandAll | boolean | false | 默认全部展开 |
| onSelect | (keys, selected, node) => void | — | 选中回调 |
| onCheck | (keys, state) => void | — | 勾选回调 |
Breadcrumb 面包屑
import { Breadcrumb } from "knight-ui";
<Breadcrumb>
<Breadcrumb.Item onClick={() => console.log("Home")}>Home</Breadcrumb.Item>
<Breadcrumb.Item href="/products">Products</Breadcrumb.Item>
<Breadcrumb.Item>Detail</Breadcrumb.Item>
</Breadcrumb>
// 路由模式
<Breadcrumb routes={[
{ name: "首页", path: "/" },
{ name: "列表", path: "/list" },
{ name: "详情" },
]} />
// 自定义分隔符
<Breadcrumb separator=">">
<Breadcrumb.Item>Home</Breadcrumb.Item>
<Breadcrumb.Item>Detail</Breadcrumb.Item>
</Breadcrumb>Breadcrumb.Item:href、onClick、icon
Steps 步骤条
import { Steps } from "knight-ui";
<Steps current={1}>
<Steps.Step title="步骤一" description="填写基本信息" />
<Steps.Step title="步骤二" description="验证身份信息" />
<Steps.Step title="步骤三" description="完成注册" />
</Steps>
// 垂直方向
<Steps direction="vertical" current={1}>
<Steps.Step title="填写信息" />
<Steps.Step title="确认提交" />
<Steps.Step title="完成" />
</Steps>
// Fill 样式
<Steps type="primary" current={1} status="error">
<Steps.Step title="步骤一" />
<Steps.Step title="步骤二" description="出错了" />
</Steps>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| current | number | — | 当前步骤 |
| status | "wait" \| "process" \| "finish" \| "error" \| "warning" | — | 状态 |
| direction | "horizontal" \| "vertical" | "horizontal" | 方向 |
| type | "primary" \| "basic" \| "nav" | "basic" | 样式类型 |
| onChange | (index: number) => void | — | 步骤切换 |
Pagination 分页
import { Pagination } from "knight-ui";
<Pagination total={200} defaultCurrent={3} onChange={(page, size) => console.log(page, size)} />
<Pagination total={500} showSizeChanger showQuickJumper />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| total | number | 必填 | 数据总数 |
| current / defaultCurrent | number | 1 | 当前页 |
| pageSize / defaultPageSize | number | — | 每页条数 |
| showSizeChanger | boolean | false | 条数切换 |
| showQuickJumper | boolean | false | 快速跳转 |
| onChange | (page, pageSize) => void | — | 页码变化回调 |
Anchor 锚点
import { Anchor } from "knight-ui";
<Anchor onChange={(key) => console.log(key)}>
<Anchor.Link href="#section-1" title="基本介绍" />
<Anchor.Link href="#section-2" title="API 参考" />
</Anchor>BackTop 回到顶部
import { BackTop } from "knight-ui";
<BackTop visibilityHeight={200} onClick={() => console.log("back to top")} />
// 指定目标容器
<BackTop target={() => document.getElementById("scroll-container")!} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| visibilityHeight | number | — | 显示阈值 |
| duration | number | — | 滚动时长(ms) |
| target | () => HTMLElement \| Window | window | 目标容器 |
Display 展示
Avatar 头像
import { Avatar } from "knight-ui";
<Avatar size="medium">Alice</Avatar>
<Avatar size="large" src="https://picsum.photos/80" alt="avatar" />
<Avatar shape="square" color="#ec4899">S</Avatar>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| size | "extra-small" \| "small" \| "default" \| "medium" \| "large" \| number | "default" | 尺寸 |
| shape | "circle" \| "square" | "circle" | 形状 |
| src | string | — | 图片地址 |
| color | string | — | 自定义颜色 |
Badge 角标
import { Badge, Button } from "knight-ui";
<Badge count={5}><Button>消息</Button></Badge>
<Badge count={120} overflowCount={99}><Button>通知</Button></Badge>
<Badge dot><span>新消息</span></Badge>
<Badge dot type="success" position="leftTop"><span>在线</span></Badge>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| count | number \| React.ReactNode | — | 角标内容 |
| dot | boolean | false | 圆点模式 |
| overflowCount | number | 99 | 溢出显示值 |
| type | "primary" \| "success" \| "warning" \| "danger" | "primary" | 类型 |
| position | "leftTop" \| "leftBottom" \| "rightTop" \| "rightBottom" | "rightTop" | 位置 |
Card 卡片
import { Card, Text, Button, Avatar } from "knight-ui";
<Card style={{ width: 360 }}
cover={<div style={{ height: 140, background: "linear-gradient(135deg, #8b5cf6, #ec4899)" }} />}
header="卡片标题"
actions={[<Button key="1" type="tertiary" size="small">操作</Button>]}
footer="底部信息"
>
<Card.Meta title="Meta 标题" description="Meta 描述" avatar={<Avatar size="small">A</Avatar>} />
</Card>
<Card bordered={false} shadows="always">
<Text>无边框阴影卡片</Text>
</Card>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| cover | React.ReactNode | — | 封面 |
| header / footer | React.ReactNode | — | 头部/底部 |
| actions | React.ReactNode[] | — | 操作区 |
| bordered | boolean | true | 边框 |
| shadows | "hover" \| "always" \| "none" | "hover" | 阴影 |
Tag 标签
import { Tag } from "knight-ui";
<Tag color="blue">蓝色标签</Tag>
<Tag type="solid" color="green">实心绿色</Tag>
<Tag type="ghost" color="orange">幽灵橙色</Tag>
<Tag closable onClose={() => console.log("closed")}>可关闭</Tag>
<Tag size="large" color="#ec4899">粉色</Tag>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "ghost" \| "solid" \| "light" | "light" | 样式 |
| color | string | — | 颜色 |
| size | "small" \| "default" \| "large" | "default" | 尺寸 |
| closable | boolean | false | 可关闭 |
| avatar | React.ReactNode | — | 头像 |
Collapse 折叠面板
import { Collapse, Text } from "knight-ui";
<Collapse defaultActiveKey={["1"]}>
<Collapse.Panel header="面板一" itemKey="1">
<Text>面板一的内容</Text>
</Collapse.Panel>
<Collapse.Panel header="面板二" itemKey="2">
<Text>面板二的内容</Text>
</Collapse.Panel>
<Collapse.Panel header="禁用面板" itemKey="3" disabled>
<Text>不可见</Text>
</Collapse.Panel>
</Collapse>
// 手风琴模式
<Collapse accordion>
<Collapse.Panel header="面板 A" itemKey="a"><Text>内容 A</Text></Collapse.Panel>
<Collapse.Panel header="面板 B" itemKey="b"><Text>内容 B</Text></Collapse.Panel>
</Collapse>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| activeKey / defaultActiveKey | string \| string[] | — | 展开面板 |
| accordion | boolean | false | 手风琴模式 |
| onChange | (activeKey) => void | — | 切换回调 |
Collapsible 轻量折叠
import { Collapsible, Button } from "knight-ui";
const [collapsed, setCollapsed] = useState(false);
<Button onClick={() => setCollapsed(!collapsed)}>{collapsed ? "展开" : "折叠"}</Button>
<Collapsible collapsed={collapsed}>
<div style={{ padding: 16, background: "#f0f0f0" }}>可折叠内容区域</div>
</Collapsible>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| collapsed | boolean | — | 折叠状态 |
| motion | boolean | true | 动画过渡 |
| keepDOM | boolean | false | 保留 DOM |
Descriptions 描述列表
import { Descriptions } from "knight-ui";
const data = [
{ key: "姓名", value: "张三" },
{ key: "手机号", value: "138****8888" },
{ key: "地址", value: "北京市朝阳区", span: 2 },
];
<Descriptions layout="horizontal" column={2} data={data} bordered />
// Item 子组件
<Descriptions column={2}>
<Descriptions.Item itemKey="创建人">李四</Descriptions.Item>
<Descriptions.Item itemKey="状态">
<Tag color="green">已完成</Tag>
</Descriptions.Item>
</Descriptions>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| data | DescriptionsData[] | — | 数据 |
| layout | "horizontal" \| "vertical" | "vertical" | 布局 |
| column | number | 3 | 列数 |
| size | "small" \| "medium" \| "large" | "medium" | 尺寸 |
| row | boolean | false | 双行模式 |
| bordered | boolean | false | 边框 |
Empty 空状态
import { Empty } from "knight-ui";
<Empty />
<Empty title="暂无数据" description="当前列表为空,请先添加数据" />
<Empty image={<IconAlertTriangle size="extraLarge" />} description="加载失败" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| image | React.ReactNode | — | 自定义图片 |
| title | React.ReactNode | — | 标题 |
| description | React.ReactNode | — | 描述 |
Image 图片
import { Image } from "knight-ui";
<Image src="https://picsum.photos/400/300" width={200} height={150} />
<Image src="https://picsum.photos/400/300" preview />
<Image src="/not-exist.jpg" fallback="https://picsum.photos/200/150" />
<Image src="/large.jpg" lazy width={300} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| src | string | — | 图片地址 |
| preview | boolean | false | 可预览 |
| fallback | string | — | 加载失败回退 |
| lazy | boolean | — | 懒加载 |
| width / height | number \| string | — | 宽高 |
List 列表
import { List, Text } from "knight-ui";
const data = ["列表项 A", "列表项 B", "列表项 C"];
<List
dataSource={data}
renderItem={(item) => <Text>{item}</Text>}
header="列表标题"
footer="底部"
bordered
/>
// 加载 / 空状态
<List dataSource={[]} loading />
<List dataSource={[]} empty={<Empty description="暂无数据" />} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| dataSource | any[] | — | 数据源 |
| renderItem | (item, index) => ReactNode | — | 渲染函数 |
| header / footer | React.ReactNode | — | 头部/底部 |
| loading | boolean | false | 加载中 |
| bordered | boolean | false | 边框 |
Table 表格
import { Table } from "knight-ui";
const columns = [
{ key: "name", title: "名称", dataIndex: "name", width: 120 },
{ key: "age", title: "年龄", dataIndex: "age", width: 80, sorter: (a, b) => a - b },
{ key: "city", title: "城市", dataIndex: "city" },
];
const data = [
{ name: "张三", age: 28, city: "北京" },
{ name: "李四", age: 32, city: "上海" },
];
<Table columns={columns} dataSource={data} rowKey="name" bordered />
<Table columns={columns} dataSource={data} pagination={{ total: 100 }} loading />
<Table columns={columns} dataSource={data} rowSelection selectedRowKeys={["张三"]} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| columns | TableColumn[] | — | 列定义 |
| dataSource | Record<string, any>[] | — | 数据源 |
| rowKey | string | — | 行唯一 key |
| pagination | boolean \| PaginationConfig | — | 分页 |
| loading | boolean | false | 加载中 |
| bordered | boolean | false | 边框 |
| striped | boolean | false | 斑马纹 |
| rowSelection | boolean | — | 行选择 |
Modal 模态框
import { Modal, Button } from "knight-ui";
const [visible, setVisible] = useState(false);
<Button type="primary" onClick={() => setVisible(true)}>打开 Modal</Button>
<Modal
title="确认操作"
visible={visible}
onOk={() => { setVisible(false); console.log("ok"); }}
onCancel={() => setVisible(false)}
>
<Text>确定要执行此操作吗?</Text>
</Modal>
// 大型 + 自定义按钮
<Modal
title="大型模态框"
visible={visible}
size="large"
okText="确认"
cancelText="取消"
centered
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
>
<div>大型模态框内容区域</div>
</Modal>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| visible | boolean | — | 显示状态 |
| title | React.ReactNode | — | 标题 |
| size | "small" \| "medium" \| "large" | "medium" | 尺寸 |
| okText / cancelText | string | — | 按钮文字 |
| maskClosable | boolean | true | 点击遮罩关闭 |
| centered | boolean | false | 居中 |
| onOk | () => void \| Promise<void> | — | 确认回调 |
| onCancel | () => void | — | 取消回调 |
SideSheet 侧边面板
import { SideSheet, Button } from "knight-ui";
const [visible, setVisible] = useState(false);
<Button onClick={() => setVisible(true)}>打开侧边面板</Button>
<SideSheet
title="详情面板"
visible={visible}
placement="right"
size="medium"
onCancel={() => setVisible(false)}
>
<div style={{ padding: 16 }}>面板内容</div>
</SideSheet>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| visible | boolean | — | 显示状态 |
| title | React.ReactNode | — | 标题 |
| placement | "left" \| "right" | "right" | 滑出方向 |
| size | "small" \| "medium" \| "large" | "medium" | 尺寸 |
| maskClosable | boolean | true | 点击遮罩关闭 |
| onCancel | () => void | — | 关闭回调 |
Dropdown 下拉菜单
import { Dropdown, Button } from "knight-ui";
const menu = [
{ key: "1", label: "选项一" },
{ key: "2", label: "选项二" },
{ key: "div", label: "", divider: true },
{ key: "3", label: "删除", danger: true },
];
<Dropdown trigger="click" menu={menu} onClickItem={(key) => console.log(key)}>
<Button>点击展开菜单</Button>
</Dropdown>
<Dropdown trigger="hover" menu={menu} position="bottomLeft">
<Button type="secondary">悬停展开</Button>
</Dropdown>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| menu | DropdownItem[] | — | 菜单项 |
| trigger | "click" \| "hover" | "click" | 触发方式 |
| position | Position | "bottom" | 弹出位置 |
| onClickItem | (key: string) => void | — | 菜单项点击 |
Popover 气泡卡片
import { Popover, Button } from "knight-ui";
<Popover trigger="click" content="这是气泡提示内容" position="bottom">
<Button>点击弹出</Button>
</Popover>
<Popover trigger="hover" title="提示标题" content={<Text>丰富的气泡内容</Text>} position="top">
<Text style={{ borderBottom: "1px dashed", cursor: "help" }}>悬停查看</Text>
</Popover>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| content | React.ReactNode | — | 内容 |
| title | React.ReactNode | — | 标题 |
| position | "top" \| "bottom" \| "left" \| "right" | "bottom" | 位置 |
| trigger | "hover" \| "click" \| "focus" \| "custom" | "hover" | 触发方式 |
| showArrow | boolean | — | 显示箭头 |
Tooltip 文字提示
import { Tooltip, Button } from "knight-ui";
<Tooltip content="这是一段提示文字" position="top">
<Button>悬停查看提示</Button>
</Tooltip>
<Tooltip content="左侧提示" position="left" theme="light">
<span>悬停文本</span>
</Tooltip>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| content | React.ReactNode | — | 提示内容 |
| position | Position | "top" | 位置 |
| trigger | "hover" \| "click" \| "focus" \| "custom" | "hover" | 触发方式 |
| theme | "dark" \| "light" | "dark" | 主题 |
Popconfirm 气泡确认框
import { Popconfirm, Button } from "knight-ui";
import { IconAlertTriangle } from "knight-ui";
// 基础用法 (默认 position="bottom", trigger="click")
<Popconfirm
title="确定删除?"
content="删除后不可恢复"
onConfirm={() => console.log("confirmed")}
onCancel={() => console.log("cancelled")}
>
<Button type="danger">删除</Button>
</Popconfirm>
// 自定义按钮文字 + 图标
<Popconfirm title="确定保存?" content="保存后覆盖原有数据"
icon={<IconAlertTriangle size="extraLarge" color="var(--ku-color-warning)" />}
okText="保存" cancelText="取消"
onConfirm={() => console.log("saved")}>
<Button type="warning">保存</Button>
</Popconfirm>
// 8 方向弹出 (position)
<Popconfirm title="确认?" position="leftTop" onConfirm={() => {}}>
<Button>左上弹出</Button>
</Popconfirm>
<Popconfirm title="确认?" position="rightBottom" onConfirm={() => {}}>
<Button>右下弹出</Button>
</Popconfirm>
// hover 触发 + 带箭头
<Popconfirm title="提示" content="悬停即可查看" trigger="hover" showArrow position="top"
onConfirm={() => {}}>
<Button type="secondary">悬停触发</Button>
</Popconfirm>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| title | React.ReactNode | — | 标题 |
| content | React.ReactNode | — | 内容 |
| position | "top" \| "bottom" \| "left" \| "right" \| "leftTop" \| "rightTop" \| "leftBottom" \| "rightBottom" | "bottom" | 弹出位置(命名规则: 第一个词=左右, 第二个词=上下) |
| trigger | "click" \| "hover" \| "focus" \| "custom" | "click" | 触发方式 |
| icon | React.ReactNode | — | 自定义图标 |
| showArrow | boolean | false | 显示箭头 |
| okText / cancelText | string | "确认" / "取消" | 按钮文字 |
| okButtonProps / cancelButtonProps | ButtonHTMLAttributes | — | 按钮额外属性 |
| visible / defaultVisible | boolean | — | 受控/非受控显示 |
| offset | number | 4 | 弹出偏移距离 |
| onConfirm | (e) => void | — | 确认回调 |
| onCancel | (e) => void | — | 取消回调 |
| onVisibleChange | (visible: boolean) => void | — | 显示状态变化回调 |
Calendar 日历
import { Calendar } from "knight-ui";
<Calendar onChange={(date) => console.log(date)} />
<Calendar disabledDate={(d) => d.getTime() < Date.now() - 86400000} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| mode | "month" \| "year" \| "day" | "month" | 视图模式 |
| disabledDate | (date) => boolean | — | 禁用日期 |
| onChange | (date: Date) => void | — | 变更回调 |
Carousel 轮播
import { Carousel } from "knight-ui";
<Carousel style={{ width: 500, height: 200 }} autoPlay interval={3000}>
<div style={{ height: 200, background: "#8b5cf6", color: "#fff" }}>Slide 1</div>
<div style={{ height: 200, background: "#22c55e", color: "#fff" }}>Slide 2</div>
<div style={{ height: 200, background: "#3b82f6", color: "#fff" }}>Slide 3</div>
</Carousel>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| autoPlay | boolean | false | 自动播放 |
| interval | number | 3000 | 间隔(ms) |
| effect | "slide" \| "fade" | "slide" | 切换效果 |
| showDots | boolean | true | 指示器 |
| showArrow | boolean | true | 箭头 |
Timeline 时间轴
import { Timeline } from "knight-ui";
<Timeline>
<Timeline.Item time="2024-01-01" type="success">项目启动</Timeline.Item>
<Timeline.Item time="2024-03-15" color="#8b5cf6">版本 v1.0 发布</Timeline.Item>
<Timeline.Item time="2024-06-01" type="warning">迭代中</Timeline.Item>
</Timeline>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| mode | "left" \| "alternate" \| "right" | "left" | 排列模式 |
| pending | React.ReactNode | — | 加载节点 |
Timeline.Item:time、dot、color、type("default" | "success" | "warning" | "danger")
ScrollList 滚动列表
import { ScrollList } from "knight-ui";
const hours = Array.from({ length: 24 }, (_, i) => ({ value: i, text: String(i).padStart(2, "0") }));
<ScrollList header="选择小时" bodyHeight={200}>
<ScrollList.Item
list={hours}
mode="wheel"
selectedIndex={12}
onSelect={(data) => console.log(data.value)}
/>
</ScrollList>ScrollList.Item:list、mode("normal" | "wheel")、cycled、selectedIndex、onSelect
Highlight 高亮
import { Highlight } from "knight-ui";
<Highlight sourceString="React 是一个用于构建用户界面的 JavaScript 库"
searchWords={["React", "JavaScript"]} />
<Highlight sourceString="Hello World" searchWords={["hello"]}
highlightStyle={{ color: "#f59e0b", background: "rgba(245,158,11,0.15)" }} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| sourceString | string | — | 源文本 |
| searchWords | string[] | — | 关键词 |
| highlightStyle | React.CSSProperties | — | 高亮样式 |
Cropper 裁剪
import { Cropper } from "knight-ui";
<Cropper src="https://picsum.photos/600/400" cropShape="rect" aspectRatio={16 / 9}
onCrop={(result) => console.log(result)} />
<Cropper src="/avatar.jpg" cropShape="round" aspectRatio={1} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| src | string | — | 图片地址 |
| cropShape | "rect" \| "round" | "rect" | 裁剪形状 |
| aspectRatio | number | — | 裁剪比例 |
| onCrop | (result: CropResult) => void | — | 裁剪回调 |
UserGuide 用户引导
import { UserGuide } from "knight-ui";
const steps = [
{ target: "#step-1", title: "第一步", content: "这是第一个引导步骤", placement: "bottom" },
{ target: "#step-2", title: "第二步", content: "这是第二个引导步骤", placement: "right" },
];
<UserGuide steps={steps} visible currentStep={0}
onChange={(s) => console.log(s)}
onSkip={() => console.log("skip")}
onFinish={() => console.log("finish")}
/>VChart 图表
import { VChart } from "knight-ui";
const data = [
{ label: "一月", value: 30 },
{ label: "二月", value: 50 },
{ label: "三月", value: 40 },
];
<VChart type="line" data={data} width={400} height={300} />
<VChart type="bar" data={data} colors={["#8b5cf6", "#22c55e", "#f59e0b"]} />
<VChart type="pie" data={data} width={300} height={300} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "line" \| "bar" \| "pie" \| "area" \| "scatter" | — | 图表类型 |
| data | { label: string; value: number }[] | — | 数据 |
| width / height | number | — | 宽高 |
| colors | string[] | — | 颜色数组 |
OverflowList 溢出列表
import { OverflowList, Tag } from "knight-ui";
const items = ["Item A", "Item B", "Item C", "Item D", "Item E", "Item F"];
<OverflowList
items={items}
minVisibleItems={3}
collapseFrom="end"
renderItem={(item) => <Tag type="light">{item}</Tag>}
overflowRender={(overflow) => <Tag type="light">+{overflow.length} 更多</Tag>}
/>
// 开头折叠
<OverflowList items={items} minVisibleItems={3} collapseFrom="start"
renderItem={(item) => <Tag color="blue">{item}</Tag>}
overflowRender={(o) => <Tag>+{o.length}</Tag>}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items | any[] | — | 数据 |
| collapseFrom | "start" \| "end" | "end" | 折叠方向 |
| minVisibleItems | number | — | 最小可见数 |
| renderItem | (item, index) => ReactNode | — | 渲染项 |
| overflowRender | (overflow) => ReactNode | — | 溢出渲染 |
Feedback 反馈
Toast 轻提示(命令式)
import { Toast } from "knight-ui";
// 快捷方法
Toast.success("操作成功");
Toast.info("提示信息");
Toast.warning("警告信息", 3000);
Toast.error("错误信息");
// 通用方法
const id = Toast.open({
content: "自定义内容",
duration: 3000,
type: "success",
position: "top",
});
Toast.close(id);
Toast.destroyAll();
// Hook 用法
const { success, error } = Toast.useToast();
success("保存成功");Notification 通知(命令式)
import { Notification } from "knight-ui";
Notification.success({ title: "成功", content: "操作已完成" });
Notification.info({ title: "提示", content: "这是一条通知" });
Notification.warning({ title: "警告", content: "请注意检查" });
Notification.error({ title: "错误", content: "操作失败" });
Notification.open({
title: "自定义",
content: "通知内容",
duration: 5000,
position: "topRight",
});
Notification.close(id);
Notification.destroyAll();Banner 横幅
import { Banner } from "knight-ui";
<Banner
visible
type="warning"
title="系统维护通知"
description="系统将于今晚 22:00-02:00 进行维护升级"
onClose={() => console.log("closed")}
/>
<Banner visible type="success" title="操作成功" fullMode bordered
actions={<Button type="primary" size="small">查看详情</Button>}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "info" \| "success" \| "warning" \| "danger" | "info" | 类型 |
| title | React.ReactNode | — | 标题 |
| description | React.ReactNode | — | 描述 |
| fullMode | boolean | — | 通栏模式 |
| bordered | boolean | — | 边框 |
| actions | React.ReactNode | — | 操作区 |
Progress 进度条
import { Progress } from "knight-ui";
<Progress percent={60} />
<Progress type="circle" percent={75} />
<Progress percent={80} strokeColor="#22c55e" status="success" />
<Progress percent={50} strokeColor={[{ percent: 30, color: "#ef4444" }, { percent: 100, color: "#f59e0b" }]} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "line" \| "circle" | "line" | 类型 |
| percent | number | — | 进度百分比 |
| strokeWidth | number | — | 线条宽度 |
| strokeColor | string \| Array | — | 颜色 |
| status | "normal" \| "success" \| "exception" | "normal" | 状态 |
| direction | "horizontal" \| "vertical" | "horizontal" | 方向 |
Skeleton 骨架屏
import { Skeleton } from "knight-ui";
// 组合使用
<Skeleton loading={isLoading} placeholder={<div>实际内容</div>}>
<Skeleton.Title />
<Skeleton.Paragraph rows={3} />
</Skeleton>
// 单独组件
<Skeleton.Avatar size="large" />
<Skeleton.Button />
<Skeleton.Image style={{ width: 200, height: 150 }} />子组件:Skeleton.Avatar、Skeleton.Title、Skeleton.Paragraph、Skeleton.Button、Skeleton.Image
Spin 加载中
import { Spin } from "knight-ui";
<Spin spinning={loading}>
<div>包裹的内容区域</div>
</Spin>
<Spin size="large" tip="加载中..." />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| spinning | boolean | true | 加载状态 |
| size | "small" \| "middle" \| "large" | "middle" | 尺寸 |
| tip | React.ReactNode | — | 提示文字 |
| delay | number | — | 延迟显示(ms) |
Feedback 反馈组件
import { Feedback } from "knight-ui";
<Feedback
type="emoji"
title="这次体验如何?"
visible
onOk={(result) => console.log(result)}
onCancel={() => setVisible(false)}
/>
<Feedback
type="radio"
title="请选择原因"
options={[
{ value: "bug", text: "有 Bug" },
{ value: "slow", text: "加载慢" },
]}
onOk={(result) => console.log(result)}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| type | "emoji" \| "text" \| "radio" \| "checkbox" \| "custom" | — | 类型 |
| title | React.ReactNode | — | 标题 |
| options | FeedbackOption[] | — | 选项 |
| onOk | (result) => void | — | 确认回调 |
Plus 增强
Markdown
import { Markdown } from "knight-ui";
const md = `# 标题
这是一段 **Markdown** 文本。
- 列表项 1
- 列表项 2
\`\`\`js
console.log("hello");
\`\`\`
`;
<Markdown source={md} />
<Markdown source={md} renderMode="preview" />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| source | string | — | Markdown 文本 |
| renderMode | "default" \| "preview" \| "raw" | "default" | 渲染模式 |
| rows | number | — | raw 模式行数 |
CodeEditor 代码编辑器
import { CodeEditor } from "knight-ui";
<CodeEditor
defaultValue="console.log('hello');"
language="javascript"
height={300}
theme="vs-dark"
onChange={(value) => console.log(value)}
/>
<CodeEditor language="typescript" readOnly showCopyBtn showFormatBtn />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| language | string | — | 语言 |
| theme | "vs-dark" \| "light" \| "hc-black" | "vs-dark" | 主题 |
| readOnly | boolean | false | 只读 |
| height / minHeight | number | — | 高度 |
| showCopyBtn / showFormatBtn | boolean | true | 复制/格式化按钮 |
| fontSize | number | — | 字号 |
| onChange | (value: string) => void | — | 变更回调 |
CodeHighlight 代码高亮
import { CodeHighlight } from "knight-ui";
const code = `function hello() {
console.log("Hello World");
}`;
<CodeHighlight code={code} language="javascript" />
<CodeHighlight code={code} language="typescript" showLineNumbers copyable />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| code | string | — | 代码文本 |
| language | string | — | 语言 |
| theme | "vs-dark" \| "light" \| "hc-black" | "vs-dark" | 主题 |
| showLineNumbers | boolean | — | 行号 |
| copyable | boolean | true | 可复制 |
JsonViewer JSON 查看器
import { JsonViewer } from "knight-ui";
<JsonViewer value={{ name: "Knight", version: "1.0.0" }} />
<JsonViewer value='{"key": "value"}' theme="light" readOnly height={300} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value | string \| object | — | JSON 内容 |
| readOnly | boolean | false | 只读 |
| height | number | — | 高度 |
| theme | "vs-dark" \| "light" | "vs-dark" | 主题 |
| onChange | (value: string) => void | — | 变更回调 |
Chat 聊天
import { Chat } from "knight-ui";
const messages = [
{ id: "1", content: "你好!", role: "user", timestamp: Date.now() },
{ id: "2", content: "你好,有什么可以帮助你的?", role: "assistant", timestamp: Date.now() },
];
<Chat
dataSource={messages}
onSend={(content) => console.log("send:", content)}
placeholder="输入消息..."
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| dataSource | ChatMessage[] | — | 消息列表 |
| loading | boolean | false | 加载中 |
| showInput | boolean | true | 显示输入框 |
| onSend | (content: string) => void | — | 发送回调 |
AudioPlayer 音频播放器
import { AudioPlayer } from "knight-ui";
<AudioPlayer src="/audio.mp3" theme="dark" />
<AudioPlayer src="/audio.mp3" autoPlay loop volume={0.5} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| src | string | — | 音频地址 |
| autoPlay | boolean | false | 自动播放 |
| loop | boolean | false | 循环 |
| theme | "dark" \| "light" | "dark" | 主题 |
| volume | number | — | 音量 0-1 |
VideoPlayer 视频播放器
import { VideoPlayer } from "knight-ui";
<VideoPlayer src="/video.mp4" poster="/poster.jpg" width={640} />
<VideoPlayer src="/video.mp4" autoPlay muted loop />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| src | string | — | 视频地址 |
| poster | string | — | 封面图 |
| autoPlay | boolean | false | 自动播放 |
| loop | boolean | false | 循环 |
| muted | boolean | — | 静音 |
DragMove 拖拽移动
import { DragMove } from "knight-ui";
<DragMove
initialPosition={{ x: 100, y: 100 }}
bounds={{ left: 0, top: 0, right: 500, bottom: 500 }}
onDragEnd={(pos) => console.log(pos)}
>
<div style={{ width: 100, height: 100, background: "#8b5cf6", cursor: "move" }}>
拖拽我
</div>
</DragMove>
// 限制 X 轴
<DragMove axis="x">
<div>只能水平拖拽</div>
</DragMove>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| initialPosition | { x, y } | — | 初始位置 |
| bounds | { top?, left?, right?, bottom? } | — | 边界 |
| axis | "x" \| "y" | — | 限制方向 |
| onDragStart / onDrag / onDragEnd | (pos) => void | — | 拖拽回调 |
HotKeys 快捷键
import { HotKeys } from "knight-ui";
<HotKeys
keys={["ctrl+s", "ctrl+shift+f"]}
onKeyDown={(e) => console.log("keydown:", e.keys)}
onKeyUp={(e) => console.log("keyup:", e.keys)}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| keys | string[] | — | 快捷键组合 |
| attach | HTMLElement \| Document | document | 挂载节点 |
| onKeyDown / onKeyUp | (e) => void | — | 按键回调 |
Lottie 动画
import { Lottie } from "knight-ui";
// 需要宿主应用注入 lottie-web 实例
<Lottie lottie={lottieWeb} src="/animation.json" autoPlay loop width={200} height={200} />
<Lottie lottie={lottieWeb} src={animationData} speed={1.5} onComplete={() => console.log("done")} />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| lottie | any | — | lottie-web 实例(由宿主注入) |
| src | string \| object | — | 动画数据或 URL |
| autoPlay | boolean | true | 自动播放 |
| loop | boolean | true | 循环 |
| speed | number | 1 | 播放速度 |
| onComplete | () => void | — | 播放完成回调 |
AI 智能
AIChatInput AI 对话输入
import { AIChatInput } from "knight-ui";
<AIChatInput
placeholder="输入你的问题..."
onSend={(value, attachments) => console.log(value, attachments)}
onChange={(value) => console.log(value)}
/>
<AIChatInput loading disabled placeholder="AI 正在回复..." />| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| value / defaultValue | string | — | 输入值 |
| placeholder | string | — | 占位符 |
| loading | boolean | false | 加载中 |
| minRows / maxRows | number | — | 行数范围 |
| attachments | Attachment[] | — | 附件列表 |
| onSend | (value, attachments) => void | — | 发送回调 |
AIChatDialogue AI 对话展示
import { AIChatDialogue } from "knight-ui";
const messages = [
{ id: "1", role: "user", content: "这段代码有什么问题?" },
{ id: "2", role: "assistant", content: "我来帮你分析一下..." },
];
<AIChatDialogue
dataSource={messages}
typing
userNickname="User"
assistantNickname="AI Assistant"
onCopy={(msg) => navigator.clipboard.writeText(msg.content)}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| dataSource | AIMessage[] | — | 消息列表 |
| typing | boolean | false | 打字效果 |
| userAvatar / assistantAvatar | string | — | 头像 |
| userNickname / assistantNickname | string | — | 昵称 |
| maxHeight | number | — | 最大高度 |
| showThinking | boolean | true | 是否显示"思考过程"块 |
| thinkingTitle | React.ReactNode | "思考过程" | 思考块标题 |
| thinkingDefaultCollapsed | boolean | false | 思考块默认是否收起 |
| thinkingBodyMaxHeight | number | 320 | 思考正文最大高度(px),超出内部滚动 |
| onCopy | (msg) => void | — | 复制回调 |
| onRetry | (msg, index) => void | — | 重试回调 |
AIMessage 思考内容支持(assistant 专用):
thinkingContent?: React.ReactNode思考/推理内容(Markdown 字符串或节点),展示为消息上方可折叠的灰色思考块;thinkingTokens?: number真实 token 数(缺省按 ~3.5 字符/token 估算);thinkingDurationMs?: number思考耗时(ms),完整消息可传,流式思考期间由组件自动计时无需传入。 流式阶段约定:仅思考时消息为{ role:"assistant", thinkingContent: 增量, status:"streaming" }(正文留空、与 content 互斥增长);结束后替换为带content(与可选thinkingDurationMs)的完整消息。<AIChatDialogue dataSource={[{ id: "2", role: "assistant", content: "回答正文", thinkingContent: "先分析…", thinkingTokens: 86, thinkingDurationMs: 12400 }]} thinkingTitle="思考过程" />
Sidebar AI 侧栏
import { Sidebar } from "knight-ui";
const items = [
{ key: "chat1", label: "对话 1", icon: <span>💬</span> },
{ key: "chat2", label: "对话 2", icon: <span>💬</span> },
];
<Sidebar
items={items}
defaultActiveKey="chat1"
header={<Text strong>AI 对话列表</Text>}
onChange={(key) => console.log(key)}
/>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| items | SidebarItem[] | — | 菜单项 |
| activeKey / defaultActiveKey | string | — | 当前选中 |
| collapsed | boolean | — | 折叠 |
| width / collapsedWidth | number | — | 宽度/折叠宽度 |
| header / footer | React.ReactNode | — | 头部/底部 |
Other 其他
ConfigProvider 全局配置
import { ConfigProvider } from "knight-ui";
<ConfigProvider componentSize="large" getPopupContainer={() => document.body}>
<App />
</ConfigProvider>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| componentSize | "small" \| "middle" \| "large" | — | 组件尺寸 |
| getPopupContainer | () => HTMLElement | — | 弹出层容器 |
| direction | "ltr" \| "rtl" | "ltr" | 文本方向 |
LocaleProvider 国际化
import { LocaleProvider } from "knight-ui";
<LocaleProvider locale={{
okText: "确认",
cancelText: "取消",
emptyText: "暂无数据",
placeholder: "请选择",
}}>
<App />
</LocaleProvider>| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| locale | Partial<Locale> | — | 语言包 |
Peer 依赖
| 包 | 版本 |
|---|---|
| react | >=18.0.0 |
| react-dom | >=18.0.0 |
License
MIT
