-
+
{data.content}
{data.url && (
diff --git a/src/components/HelperGuide/style.module.scss b/src/components/HelperGuide/style.module.scss
index 13a88ccb..be8a4dde 100644
--- a/src/components/HelperGuide/style.module.scss
+++ b/src/components/HelperGuide/style.module.scss
@@ -1,21 +1,44 @@
.helper-guide {
color: var(--font-color-grey);
line-height: 20px;
- height: 20px;
+ min-height: 20px;
+ width: 100%;
+ max-width: 100%;
+ display: block;
}
.inner {
background: var(--primary-color-1);
border-radius: var(--radius-default, 2px);
padding: 0 8px;
-
+ width: 100%;
+ display: flex;
+ align-items: center;
+ min-height: 20px;
+
:global {
+ .ant-space {
+ width: 100%;
+ display: flex;
+ }
+
.ant-space-item {
height: 20px;
line-height: 20px;
font-size: 12px;
}
+ /* 确保内容项能够收缩 */
+ .ant-space-item:last-child {
+ flex-shrink: 0; /* 链接项不收缩 */
+ }
+
+ .ant-space-item:nth-child(2) {
+ flex: 1;
+ min-width: 0;
+ overflow: hidden;
+ }
+
.iconfont--color {
display: block;
margin-top: 2px;
@@ -25,13 +48,25 @@
}
.content {
- max-width: 216px;
+ display: block;
+ max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
- display: block;
}
.link {
font-size: 12px;
+ white-space: nowrap;
+ flex-shrink: 0; /* 防止链接收缩 */
+}
+
+/* 在表单项中的 HelperGuide 样式调整 */
+:global {
+ .ant-form-item {
+ .helper-guide {
+ margin-top: 4px;
+ max-width: 100%;
+ }
+ }
}
diff --git a/src/components/HistoryStore/README.md b/src/components/HistoryStore/README.md
index 1851c45c..a5f2a9e8 100644
--- a/src/components/HistoryStore/README.md
+++ b/src/components/HistoryStore/README.md
@@ -2,45 +2,75 @@
### 概述
-历史记录提示
+HistoryStore 是一个历史记录管理组件,用于保存和展示用户的操作历史记录(如搜索记录、选择记录等)。它利用 localStorage 持久化存储数据,在用户再次访问时可以快速选择历史记录,提升用户体验。
+
+**核心特性**
+
+- **持久化存储**:基于 localStorage 实现数据持久化,刷新页面后数据不丢失
+- **多场景支持**:通过 storeName 属性区分不同场景的历史记录,互不干扰
+- **智能去重**:自动去除重复的历史记录,相同值只会保留最新的一次
+- **数量限制**:可配置最大保存数量,避免占用过多存储空间
+- **灵活触发**:支持通过焦点、点击等多种方式触发历史记录展示
+- **Render Props**:通过 render props 模式提供完整的控制能力,可自定义触发逻辑
+
+**适用场景**
+
+- 搜索框历史记录:保存用户的搜索关键词,方便快速重新搜索
+- 下拉框选择历史:保存用户选择过的选项,提供快捷选择入口
+- 过滤器历史:保存用户设置过的过滤条件,一键应用历史配置
+- 其他需要记录用户操作历史的场景
### 示例
#### 示例代码
-- 这里填写示例标题
-- 这里填写示例说明
+- 搜索框历史记录
+- 展示基础用法,搜索框获取焦点时显示历史记录
- _HistoryStore(@components/HistoryStore),antd(antd)
```jsx
const { default: HistoryStore } = _HistoryStore;
-const { Input } = antd;
-const { useState } = React;
+const { Input, Space, Card, Typography } = antd;
+
+const { Text } = Typography;
+
const BaseExample = () => {
- const [value, setValue] = useState("");
return (
- {
- setValue(value);
- }}
- >
- {({ appendHistory, openHistory }) => (
- {
- setValue(e.target.value);
+
+
+ {
+ console.log('选中历史记录:', value, item);
}}
- onFocus={openHistory}
- onSearch={(value) => {
- appendHistory({
- value,
- label: value,
- });
- }}
- />
- )}
-
+ >
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+ 基础用法:搜索框获取焦点时显示历史记录,点击历史记录标签或回车搜索后,
+ 该记录会被保存到历史记录中。
+
+
+ 历史记录使用 localStorage 持久化存储,刷新页面后仍然可用。
+
+
+
+
);
};
@@ -48,7 +78,609 @@ render();
```
+- 自定义配置
+- 展示 maxLength、label 等配置属性的用法
+- _HistoryStore(@components/HistoryStore),antd(antd)
+
+```jsx
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Space, Card, Typography, Divider } = antd;
+
+const { Text } = Typography;
+
+const CustomConfigExample = () => {
+ return (
+
+
+
+
+
默认配置(最多5条,标题"最近搜索"):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
自定义最大数量(最多10条):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
自定义标题("搜索历史"):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
不限制数量(maxLength={0}):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
+ 通过 maxLength、label 等属性可以自定义历史记录的配置。
+ maxLength 为 0 时不限制保存数量,但建议设置合理的最大值以避免占用过多存储空间。
+
+
+
+ );
+};
+
+render();
+
+```
+
+- Select 组件历史记录
+- 展示与 Select 组件结合使用,记录选择历史
+- _HistoryStore(@components/HistoryStore),antd(antd)
+
+```jsx
+const { default: HistoryStore } = _HistoryStore;
+const { Select, Space, Card, Typography, Input } = antd;
+
+const { Text } = Typography;
+
+const SelectExample = () => {
+ const departmentOptions = [
+ { label: '技术部', value: 'tech' },
+ { label: '产品部', value: 'product' },
+ { label: '运营部', value: 'operation' },
+ { label: '市场部', value: 'marketing' },
+ { label: '人力资源部', value: 'hr' },
+ { label: '财务部', value: 'finance' }
+ ];
+
+ return (
+
+
+
+
+
部门选择:
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
城市选择:
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+ HistoryStore 可以与 Select 组件结合使用,记录用户的选择历史。
+ 通过 storeName 区分不同的历史记录场景,互不干扰。
+ 使用 onDropdownVisibleChange 控制下拉框的打开状态,实现历史记录和选项列表的切换。
+
+
+
+ );
+};
+
+render();
+
+```
+
+- 多个独立存储
+- 展示通过不同 storeName 创建多个独立的历史记录
+- _HistoryStore(@components/HistoryStore),antd(antd)
+
+```jsx
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Select, Space, Card, Typography, Divider } = antd;
+
+const { Text } = Typography;
+
+const MultipleStoresExample = () => {
+ return (
+
+
+
+
+
用户搜索(storeName: user_search):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
订单搜索(storeName: order_search):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
部门筛选(storeName: department_filter):
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
状态筛选(storeName: status_filter):
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+ 通过不同的 storeName 可以创建多个独立的历史记录存储,每个存储互不干扰。
+ 这样可以在同一个页面中使用多个 HistoryStore 组件,分别记录不同操作的历史记录。
+ 常用于多个搜索框、多个筛选器等场景。
+
+
+
+ );
+};
+
+render();
+
+```
+
+- 真实业务场景
+- 展示在订单管理页面中的实际应用
+- _HistoryStore(@components/HistoryStore),antd(antd)
+
+```jsx
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Select, Button, Space, Table, Card, Typography, Tag } = antd;
+
+const { Text } = Typography;
+
+const RealScenarioExample = () => {
+ const [filters, setFilters] = React.useState({});
+
+ const columns = [
+ {
+ title: '订单号',
+ dataIndex: 'orderNo',
+ key: 'orderNo'
+ },
+ {
+ title: '客户姓名',
+ dataIndex: 'customerName',
+ key: 'customerName'
+ },
+ {
+ title: '金额',
+ dataIndex: 'amount',
+ key: 'amount',
+ render: (amount) => `¥${amount}`
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ render: (status) => {
+ const statusMap = {
+ pending: 待处理,
+ processing: 处理中,
+ completed: 已完成,
+ cancelled: 已取消
+ };
+ return statusMap[status] || status;
+ }
+ },
+ {
+ title: '创建时间',
+ dataIndex: 'createTime',
+ key: 'createTime'
+ }
+ ];
+
+ const mockData = [
+ {
+ key: '1',
+ orderNo: 'ORD202401001',
+ customerName: '张三',
+ amount: 1200.00,
+ status: 'completed',
+ createTime: '2024-01-15 10:30:00'
+ },
+ {
+ key: '2',
+ orderNo: 'ORD202401002',
+ customerName: '李四',
+ amount: 3500.00,
+ status: 'processing',
+ createTime: '2024-01-15 11:20:00'
+ },
+ {
+ key: '3',
+ orderNo: 'ORD202401003',
+ customerName: '王五',
+ amount: 890.00,
+ status: 'pending',
+ createTime: '2024-01-15 14:45:00'
+ }
+ ];
+
+ return (
+
+
+
+
+
+ 订单搜索:
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ setFilters({ ...filters, keyword: value });
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+ 状态:
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+
+ 当前筛选条件:{Object.keys(filters).length > 0 ? JSON.stringify(filters) : '无'}
+
+
+
+
+
+
+
+
+
+ 真实业务场景示例:在订单管理页面中,使用两个独立的 HistoryStore 组件,
+ 分别记录订单搜索历史和状态筛选历史。这样用户可以快速选择之前的搜索条件,
+ 提高操作效率。通过不同的 storeName 确保两个历史记录互不干扰。
+
+
+
+ );
+};
+
+render();
+
+```
+
### API
-|属性名|说明|类型|默认值|
-| --- | --- | --- | --- |
+### HistoryStore
+
+HistoryStore 组件用于管理用户的历史记录,支持将搜索、选择等操作保存到 localStorage,并在需要时展示历史记录列表供用户快速选择。
+
+#### 属性说明
+
+| 属性名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| className | string | 否 | - | 自定义类名 |
+| overlayClassName | string | 否 | - | 弹窗内容的自定义类名 |
+| storeName | string | 否 | 'HISTORY_STORE_KEY' | localStorage 的键名,用于区分不同场景的历史记录 |
+| maxLength | number | 否 | 5 | 最多保存的历史记录数量,为 0 时不限制 |
+| label | string | 否 | '最近搜索' | 历史记录列表的标题文字 |
+| children | function | 是 | - | 子组件,接收 render props |
+| onSelect | function | 否 | - | 选中历史记录时的回调函数,接收参数:(value, item) |
+| zIndex | number | 否 | - | 弹窗的 z-index 层级 |
+| getPopupContainer | function | 否 | - | 获取弹窗容器的函数 |
+
+#### Render Props
+
+children 是一个函数,接收以下参数:
+
+| 参数名 | 类型 | 说明 |
+|--------|------|------|
+| open | boolean | 弹窗是否打开 |
+| openHistory | function | 打开历史记录弹窗的方法 |
+| appendHistory | function | 添加历史记录的方法,参数:{value, label} |
+| setOnSelect | function | 设置选中回调的方法,参数:callback |
+| close | function | 关闭弹窗的方法 |
+
+#### 历史记录数据格式
+
+每条历史记录是一个对象,包含以下字段:
+
+| 字段名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| value | string | 是 | 历史记录的值 |
+| label | string | 是 | 历史记录的显示文本 |
diff --git a/src/components/HistoryStore/doc/api.md b/src/components/HistoryStore/doc/api.md
index 0a387583..2f446a78 100644
--- a/src/components/HistoryStore/doc/api.md
+++ b/src/components/HistoryStore/doc/api.md
@@ -1,2 +1,38 @@
-|属性名|说明|类型|默认值|
-| --- | --- | --- | --- |
+### HistoryStore
+
+HistoryStore 组件用于管理用户的历史记录,支持将搜索、选择等操作保存到 localStorage,并在需要时展示历史记录列表供用户快速选择。
+
+#### 属性说明
+
+| 属性名 | 类型 | 必填 | 默认值 | 说明 |
+|--------|------|------|--------|------|
+| className | string | 否 | - | 自定义类名 |
+| overlayClassName | string | 否 | - | 弹窗内容的自定义类名 |
+| storeName | string | 否 | 'HISTORY_STORE_KEY' | localStorage 的键名,用于区分不同场景的历史记录 |
+| maxLength | number | 否 | 5 | 最多保存的历史记录数量,为 0 时不限制 |
+| label | string | 否 | '最近搜索' | 历史记录列表的标题文字 |
+| children | function | 是 | - | 子组件,接收 render props |
+| onSelect | function | 否 | - | 选中历史记录时的回调函数,接收参数:(value, item) |
+| zIndex | number | 否 | - | 弹窗的 z-index 层级 |
+| getPopupContainer | function | 否 | - | 获取弹窗容器的函数 |
+
+#### Render Props
+
+children 是一个函数,接收以下参数:
+
+| 参数名 | 类型 | 说明 |
+|--------|------|------|
+| open | boolean | 弹窗是否打开 |
+| openHistory | function | 打开历史记录弹窗的方法 |
+| appendHistory | function | 添加历史记录的方法,参数:{value, label} |
+| setOnSelect | function | 设置选中回调的方法,参数:callback |
+| close | function | 关闭弹窗的方法 |
+
+#### 历史记录数据格式
+
+每条历史记录是一个对象,包含以下字段:
+
+| 字段名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| value | string | 是 | 历史记录的值 |
+| label | string | 是 | 历史记录的显示文本 |
diff --git a/src/components/HistoryStore/doc/base.js b/src/components/HistoryStore/doc/base.js
index 3a6fd497..064f638a 100644
--- a/src/components/HistoryStore/doc/base.js
+++ b/src/components/HistoryStore/doc/base.js
@@ -1,30 +1,44 @@
const { default: HistoryStore } = _HistoryStore;
-const { Input } = antd;
-const { useState } = React;
+const { Input, Space, Card, Typography } = antd;
+
+const { Text } = Typography;
+
const BaseExample = () => {
- const [value, setValue] = useState("");
return (
- {
- setValue(value);
- }}
- >
- {({ appendHistory, openHistory }) => (
- {
- setValue(e.target.value);
+
+
+ {
+ console.log('选中历史记录:', value, item);
}}
- onFocus={openHistory}
- onSearch={(value) => {
- appendHistory({
- value,
- label: value,
- });
- }}
- />
- )}
-
+ >
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+ 基础用法:搜索框获取焦点时显示历史记录,点击历史记录标签或回车搜索后,
+ 该记录会被保存到历史记录中。
+
+
+ 历史记录使用 localStorage 持久化存储,刷新页面后仍然可用。
+
+
+
+
);
};
diff --git a/src/components/HistoryStore/doc/custom-config.js b/src/components/HistoryStore/doc/custom-config.js
new file mode 100644
index 00000000..da76730e
--- /dev/null
+++ b/src/components/HistoryStore/doc/custom-config.js
@@ -0,0 +1,105 @@
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Space, Card, Typography, Divider } = antd;
+
+const { Text } = Typography;
+
+const CustomConfigExample = () => {
+ return (
+
+
+
+
+
默认配置(最多5条,标题"最近搜索"):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
自定义最大数量(最多10条):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
自定义标题("搜索历史"):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
不限制数量(maxLength={0}):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
+ 通过 maxLength、label 等属性可以自定义历史记录的配置。
+ maxLength 为 0 时不限制保存数量,但建议设置合理的最大值以避免占用过多存储空间。
+
+
+
+ );
+};
+
+render(
);
diff --git a/src/components/HistoryStore/doc/example.json b/src/components/HistoryStore/doc/example.json
index 8f07ec8c..037c7199 100644
--- a/src/components/HistoryStore/doc/example.json
+++ b/src/components/HistoryStore/doc/example.json
@@ -2,8 +2,8 @@
"isFull": false,
"list": [
{
- "title": "这里填写示例标题",
- "description": "这里填写示例说明",
+ "title": "搜索框历史记录",
+ "description": "展示基础用法,搜索框获取焦点时显示历史记录",
"code": "./base.js",
"scope": [
{
@@ -15,6 +15,66 @@
"packageName": "antd"
}
]
+ },
+ {
+ "title": "自定义配置",
+ "description": "展示 maxLength、label 等配置属性的用法",
+ "code": "./custom-config.js",
+ "scope": [
+ {
+ "name": "_HistoryStore",
+ "packageName": "@components/HistoryStore"
+ },
+ {
+ "name": "antd",
+ "packageName": "antd"
+ }
+ ]
+ },
+ {
+ "title": "Select 组件历史记录",
+ "description": "展示与 Select 组件结合使用,记录选择历史",
+ "code": "./select.js",
+ "scope": [
+ {
+ "name": "_HistoryStore",
+ "packageName": "@components/HistoryStore"
+ },
+ {
+ "name": "antd",
+ "packageName": "antd"
+ }
+ ]
+ },
+ {
+ "title": "多个独立存储",
+ "description": "展示通过不同 storeName 创建多个独立的历史记录",
+ "code": "./multiple-stores.js",
+ "scope": [
+ {
+ "name": "_HistoryStore",
+ "packageName": "@components/HistoryStore"
+ },
+ {
+ "name": "antd",
+ "packageName": "antd"
+ }
+ ]
+ },
+ {
+ "title": "真实业务场景",
+ "description": "展示在订单管理页面中的实际应用",
+ "code": "./real-scenario.js",
+ "scope": [
+ {
+ "name": "_HistoryStore",
+ "packageName": "@components/HistoryStore"
+ },
+ {
+ "name": "antd",
+ "packageName": "antd"
+ }
+ ]
}
]
}
diff --git a/src/components/HistoryStore/doc/multiple-stores.js b/src/components/HistoryStore/doc/multiple-stores.js
new file mode 100644
index 00000000..f95d085e
--- /dev/null
+++ b/src/components/HistoryStore/doc/multiple-stores.js
@@ -0,0 +1,145 @@
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Select, Space, Card, Typography, Divider } = antd;
+
+const { Text } = Typography;
+
+const MultipleStoresExample = () => {
+ return (
+
+
+
+
+
用户搜索(storeName: user_search):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
订单搜索(storeName: order_search):
+
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+
+
+
+
部门筛选(storeName: department_filter):
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
状态筛选(storeName: status_filter):
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+ 通过不同的 storeName 可以创建多个独立的历史记录存储,每个存储互不干扰。
+ 这样可以在同一个页面中使用多个 HistoryStore 组件,分别记录不同操作的历史记录。
+ 常用于多个搜索框、多个筛选器等场景。
+
+
+
+ );
+};
+
+render(
);
diff --git a/src/components/HistoryStore/doc/real-scenario.js b/src/components/HistoryStore/doc/real-scenario.js
new file mode 100644
index 00000000..886fc1ff
--- /dev/null
+++ b/src/components/HistoryStore/doc/real-scenario.js
@@ -0,0 +1,170 @@
+const { default: HistoryStore } = _HistoryStore;
+const { Input, Select, Button, Space, Table, Card, Typography, Tag } = antd;
+
+const { Text } = Typography;
+
+const RealScenarioExample = () => {
+ const [filters, setFilters] = React.useState({});
+
+ const columns = [
+ {
+ title: '订单号',
+ dataIndex: 'orderNo',
+ key: 'orderNo'
+ },
+ {
+ title: '客户姓名',
+ dataIndex: 'customerName',
+ key: 'customerName'
+ },
+ {
+ title: '金额',
+ dataIndex: 'amount',
+ key: 'amount',
+ render: (amount) => `¥${amount}`
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ render: (status) => {
+ const statusMap = {
+ pending:
待处理,
+ processing:
处理中,
+ completed:
已完成,
+ cancelled:
已取消
+ };
+ return statusMap[status] || status;
+ }
+ },
+ {
+ title: '创建时间',
+ dataIndex: 'createTime',
+ key: 'createTime'
+ }
+ ];
+
+ const mockData = [
+ {
+ key: '1',
+ orderNo: 'ORD202401001',
+ customerName: '张三',
+ amount: 1200.00,
+ status: 'completed',
+ createTime: '2024-01-15 10:30:00'
+ },
+ {
+ key: '2',
+ orderNo: 'ORD202401002',
+ customerName: '李四',
+ amount: 3500.00,
+ status: 'processing',
+ createTime: '2024-01-15 11:20:00'
+ },
+ {
+ key: '3',
+ orderNo: 'ORD202401003',
+ customerName: '王五',
+ amount: 890.00,
+ status: 'pending',
+ createTime: '2024-01-15 14:45:00'
+ }
+ ];
+
+ return (
+
+
+
+
+
+ 订单搜索:
+
+ {({ appendHistory, openHistory }) => (
+ {
+ if (value) {
+ setFilters({ ...filters, keyword: value });
+ appendHistory({ value, label: value });
+ }
+ }}
+ />
+ )}
+
+
+
+
+ 状态:
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+
+ 当前筛选条件:{Object.keys(filters).length > 0 ? JSON.stringify(filters) : '无'}
+
+
+
+
+
+
+
+
+
+ 真实业务场景示例:在订单管理页面中,使用两个独立的 HistoryStore 组件,
+ 分别记录订单搜索历史和状态筛选历史。这样用户可以快速选择之前的搜索条件,
+ 提高操作效率。通过不同的 storeName 确保两个历史记录互不干扰。
+
+
+
+ );
+};
+
+render(
);
diff --git a/src/components/HistoryStore/doc/select.js b/src/components/HistoryStore/doc/select.js
new file mode 100644
index 00000000..edc22843
--- /dev/null
+++ b/src/components/HistoryStore/doc/select.js
@@ -0,0 +1,114 @@
+const { default: HistoryStore } = _HistoryStore;
+const { Select, Space, Card, Typography, Input } = antd;
+
+const { Text } = Typography;
+
+const SelectExample = () => {
+ const departmentOptions = [
+ { label: '技术部', value: 'tech' },
+ { label: '产品部', value: 'product' },
+ { label: '运营部', value: 'operation' },
+ { label: '市场部', value: 'marketing' },
+ { label: '人力资源部', value: 'hr' },
+ { label: '财务部', value: 'finance' }
+ ];
+
+ return (
+
+
+
+
+
部门选择:
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
城市选择:
+
+
+ {({ appendHistory, openHistory, close, open }) => (
+
+
+
+
+
+
+
+
+ HistoryStore 可以与 Select 组件结合使用,记录用户的选择历史。
+ 通过 storeName 区分不同的历史记录场景,互不干扰。
+ 使用 onDropdownVisibleChange 控制下拉框的打开状态,实现历史记录和选项列表的切换。
+
+
+
+ );
+};
+
+render(
);
diff --git a/src/components/HistoryStore/doc/summary.md b/src/components/HistoryStore/doc/summary.md
index dd859a8d..50653997 100644
--- a/src/components/HistoryStore/doc/summary.md
+++ b/src/components/HistoryStore/doc/summary.md
@@ -1 +1,17 @@
-历史记录提示
+HistoryStore 是一个历史记录管理组件,用于保存和展示用户的操作历史记录(如搜索记录、选择记录等)。它利用 localStorage 持久化存储数据,在用户再次访问时可以快速选择历史记录,提升用户体验。
+
+**核心特性**
+
+- **持久化存储**:基于 localStorage 实现数据持久化,刷新页面后数据不丢失
+- **多场景支持**:通过 storeName 属性区分不同场景的历史记录,互不干扰
+- **智能去重**:自动去除重复的历史记录,相同值只会保留最新的一次
+- **数量限制**:可配置最大保存数量,避免占用过多存储空间
+- **灵活触发**:支持通过焦点、点击等多种方式触发历史记录展示
+- **Render Props**:通过 render props 模式提供完整的控制能力,可自定义触发逻辑
+
+**适用场景**
+
+- 搜索框历史记录:保存用户的搜索关键词,方便快速重新搜索
+- 下拉框选择历史:保存用户选择过的选项,提供快捷选择入口
+- 过滤器历史:保存用户设置过的过滤条件,一键应用历史配置
+- 其他需要记录用户操作历史的场景
diff --git a/src/components/Icon/README.md b/src/components/Icon/README.md
index fb7c8faf..b617a676 100644
--- a/src/components/Icon/README.md
+++ b/src/components/Icon/README.md
@@ -1,12 +1,119 @@
-# Icon
+
+# react-icon
+
+
+### 描述
+
+用于将一个font或svg展示为一个图标组件.
+
+
+### 安装
+
+```shell
+npm i --save @kne/react-icon
+```
+
### 概述
-可以显示一个图标,图标必须在字体文件中被定义过
+### Iconfont
+
+`Iconfont` 是一个基于字体图标的 React 组件,支持两种模式:
+
+- **单色模式**:使用传统字体图标渲染
+- **多彩模式**:通过 SVG 方式渲染彩色图标
+
+#### 基础图标
+```jsx
+
+```
+
+#### 指定尺寸
+```jsx
+
+```
+
+#### 多彩图标模式
+```jsx
+
+```
+
+#### 注意事项
+
+1. 需要预先引入对应的字体文件/CSS
+2. 多彩模式需要确保 SVG 资源可用
+3. 组件会自动处理 `icon-` 前缀(无需手动添加)
+
+**以上资源可以通过`FontLoader`进行加载**
+
+### FontLoader
+
+`FontLoader` 是一个用于动态加载/卸载字体资源的 React 组件,具有以下特性:
+
+- 按需加载字体文件
+- 自动卸载机制(组件卸载时)
+- 纯逻辑组件(无UI渲染)
+
+#### 加载本地字体
+```jsx
+
+```
+
+#### 加载CDN字体
+```jsx
+
+```
+
+#### 注意事项
+
+1. 需要配合 `@font-face` CSS 规则使用
+2. 字体名称(`name`)需与CSS定义保持一致
+3. 建议在应用根组件或路由组件中使用
+4. 多次加载同名字体时会自动去重
+
+### loadFont
+
+该函数提供了动态加载字体资源的功能,主要包含两个实用函数:
+
+1. **路径处理函数** - `getLastFolderName`
+ - 从文件路径中提取最后一个非空文件夹名
+ - 自动处理路径末尾的冗余斜杠
+
+2. **字体加载函数** - `loadFont`
+ - 智能避免重复加载相同字体
+ - 支持通过JS脚本方式加载字体资源
+ - 自动使用路径最后一段作为默认字体名称
+#### 基本用法
+```javascript
+import { loadFont } from './loadFont';
+
+// 加载字体(自动使用路径最后一段作为名称)
+await loadFont('/assets/fonts/roboto/roboto.js');
+
+// 指定字体名称
+await loadFont('/assets/fonts/roboto/main.js', 'Roboto');
+```
+
+#### 实现特点
+1. **防重复加载**:通过检查head中是否已存在相同href的script标签
+2. **路径标准化**:自动处理路径末尾的冗余斜杠
+3. **容错处理**:过滤路径中的空字符串部分
+
+#### 注意事项
+1. 当前仅支持通过.js文件加载字体
+2. 需要确保字体JS文件符合标准格式
+3. 在浏览器环境中使用,依赖document对象
### 示例(全屏)
+
#### 示例样式
```scss
@@ -33,81 +140,80 @@
- 这里填写示例标题
- 这里填写示例说明
-- _Icon(@components/Icon),antd(antd),ReactFetch(@kne/react-fetch),Global(@components/Global),_axios(axios),remoteLoader(@kne/remote-loader)
+- _Icon(@kne/react-icon),antd(antd),ReactFetch(@kne/react-fetch),_axios(axios),remoteLoader(@kne/remote-loader)
```jsx
-const { default: Icon } = _Icon;
-const { Slider, Space, Typography } = antd;
-const { useState } = React;
-const { createWithFetch } = ReactFetch;
-const { loadFont } = Global;
-const { default: axios } = _axios;
-const { createWithRemoteLoader } = remoteLoader;
+const {default: Icon} = _Icon;
+const {Slider, Space, Typography} = antd;
+const {useState} = React;
+const {createWithFetch} = ReactFetch;
+const {default: axios} = _axios;
+const {createWithRemoteLoader} = remoteLoader;
const BaseExample = createWithRemoteLoader({
- modules: ["components-iconfont:Font"],
-})(({ remoteModules }) => {
- const [Font] = remoteModules;
- const [value, setValue] = useState(30);
- return (
-
-
- 调整大小:
-
- {value}px
-
- {
-
- {({ list }) => {
- return (
-
- {list.map(({ name, font_class }) => {
- return (
-
-
- ",
- }}
- >
- {font_class}
-
- {name}
-
- );
- })}
-
- );
- }}
-
- }
-
- );
+ modules: ["components-iconfont:Font"],
+})(({remoteModules}) => {
+ const [Font] = remoteModules;
+ const [value, setValue] = useState(30);
+ return (
+
+
+ 调整大小:
+
+ {value}px
+
+ {
+
+ {({list}) => {
+ return (
+
+ {list.map(({name, font_class}) => {
+ return (
+
+
+ ",
+ }}
+ >
+ {font_class}
+
+ {name}
+
+ );
+ })}
+
+ );
+ }}
+
+ }
+
+ );
});
-render(
);
+render(
);
```
- 这里填写示例标题
- 这里填写示例说明
-- _Icon(@components/Icon),antd(antd),ReactFetch(@kne/react-fetch),Global(@components/Global),_axios(axios),remoteLoader(@kne/remote-loader)
+- _Icon(@kne/react-icon),antd(antd),ReactFetch(@kne/react-fetch),_axios(axios),remoteLoader(@kne/remote-loader)
```jsx
const { default: Icon } = _Icon;
@@ -173,11 +279,43 @@ render(
);
```
+
### API
-|属性名| 说明 |类型| 默认值 |
-| --- |---------------| --- |-------|
-|type| 图标类型,参考示例下的字符串 |string | - |
-| colorful | 是否是彩色图标 | boolean| false |
-| prefix| 图标前缀 |string| "" |
-|size| 图标大小 |number| - |
+### Iconfont
+
+| 属性 | 类型 | 默认值 | 说明 |
+|-----------------|---------------|--------------|------------------------|
+| `type` | string | **必填** | 图标名称(如 `'home'`) |
+| `colorful` | boolean | `false` | 是否启用多彩模式 |
+| `className` | string | - | 自定义 CSS 类名 |
+| `fontClassName` | string | `'iconfont'` | 字体图标基础类名 |
+| `size` | number/string | - | 图标尺寸(如 `20` 或 `'2em'`) |
+| `style` | object | - | 行内样式对象 |
+| `prefix` | string | `''` | 图标名前缀(自动处理 `icon-` 前缀) |
+| `...other` | any | - | 其他透传的 DOM 属性 |
+
+### FontLoader
+
+| 属性 | 类型 | 必填 | 说明 |
+|------|------|------|------|
+| `path` | string | 是 | 字体文件路径(支持相对/绝对路径) |
+| `name` | string | 是 | 注册的字体名称(用于CSS引用) |
+
+### `getLastFolderName(path)`
+```javascript
+/**
+ * 从文件路径中提取最后一个文件夹名
+ * @param {string} path - 文件路径
+ * @return {string} 最后一个非空文件夹名
+ */
+```
+
+### `loadFont(path, name)`
+```javascript
+/**
+ * 动态加载字体资源
+ * @param {string} path - 字体资源路径(.js)
+ * @param {string} [name] - 可选字体名称,未提供时使用路径最后一段
+ */
+```
diff --git a/src/components/Icon/doc/api.md b/src/components/Icon/doc/api.md
deleted file mode 100644
index 07a7b6b3..00000000
--- a/src/components/Icon/doc/api.md
+++ /dev/null
@@ -1,6 +0,0 @@
-|属性名| 说明 |类型| 默认值 |
-| --- |---------------| --- |-------|
-|type| 图标类型,参考示例下的字符串 |string | - |
-| colorful | 是否是彩色图标 | boolean| false |
-| prefix| 图标前缀 |string| "" |
-|size| 图标大小 |number| - |
diff --git a/src/components/Icon/doc/base.js b/src/components/Icon/doc/base.js
deleted file mode 100644
index c887e341..00000000
--- a/src/components/Icon/doc/base.js
+++ /dev/null
@@ -1,66 +0,0 @@
-const { default: Icon } = _Icon;
-const { Slider, Space, Typography } = antd;
-const { useState } = React;
-const { createWithFetch } = ReactFetch;
-const { loadFont } = Global;
-const { default: axios } = _axios;
-const { createWithRemoteLoader } = remoteLoader;
-
-const BaseExample = createWithRemoteLoader({
- modules: ["components-iconfont:Font"],
-})(({ remoteModules }) => {
- const [Font] = remoteModules;
- const [value, setValue] = useState(30);
- return (
-
-
- 调整大小:
-
- {value}px
-
- {
-
- {({ list }) => {
- return (
-
- {list.map(({ name, font_class }) => {
- return (
-
-
- ",
- }}
- >
- {font_class}
-
- {name}
-
- );
- })}
-
- );
- }}
-
- }
-
- );
-});
-
-render(
);
diff --git a/src/components/Icon/doc/colorful.js b/src/components/Icon/doc/colorful.js
deleted file mode 100644
index 4eb8f75e..00000000
--- a/src/components/Icon/doc/colorful.js
+++ /dev/null
@@ -1,60 +0,0 @@
-const { default: Icon } = _Icon;
-const { Space, Slider, Typography } = antd;
-const { useState } = React;
-const { createWithFetch } = ReactFetch;
-const { createWithRemoteLoader } = remoteLoader;
-const { default: axios } = _axios;
-
-const BaseExample = createWithRemoteLoader({
- modules: ["components-iconfont:ColorfulFont"],
-})(({ remoteModules }) => {
- const [ColorfulFont] = remoteModules;
- const [value, setValue] = useState(30);
- return (
-
-
- 调整大小:
-
- {value}px
-
-
- {({ list }) => (
-
- {list.map(({ name }) => {
- return (
-
-
- ",
- }}
- >
- {name}
-
-
- );
- })}
-
- )}
-
-
- );
-});
-
-render(
);
diff --git a/src/components/Icon/doc/example.json b/src/components/Icon/doc/example.json
index 438113ae..c3bc3b2a 100644
--- a/src/components/Icon/doc/example.json
+++ b/src/components/Icon/doc/example.json
@@ -1,67 +1,3 @@
{
- "isFull": true,
- "list": [
- {
- "title": "这里填写示例标题",
- "description": "这里填写示例说明",
- "code": "./base.js",
- "scope": [
- {
- "name": "_Icon",
- "packageName": "@components/Icon"
- },
- {
- "name": "antd",
- "packageName": "antd"
- },
- {
- "name": "ReactFetch",
- "packageName": "@kne/react-fetch"
- },
- {
- "name": "Global",
- "packageName": "@components/Global"
- },
- {
- "name": "_axios",
- "packageName": "axios"
- },
- {
- "name": "remoteLoader",
- "packageName": "@kne/remote-loader"
- }
- ]
- },
- {
- "title": "这里填写示例标题",
- "description": "这里填写示例说明",
- "code": "./colorful.js",
- "scope": [
- {
- "name": "_Icon",
- "packageName": "@components/Icon"
- },
- {
- "name": "antd",
- "packageName": "antd"
- },
- {
- "name": "ReactFetch",
- "packageName": "@kne/react-fetch"
- },
- {
- "name": "Global",
- "packageName": "@components/Global"
- },
- {
- "name": "_axios",
- "packageName": "axios"
- },
- {
- "name": "remoteLoader",
- "packageName": "@kne/remote-loader"
- }
- ]
- }
- ]
+ "reference": "@kne/react-icon"
}
diff --git a/src/components/Icon/doc/style.scss b/src/components/Icon/doc/style.scss
deleted file mode 100644
index fc0b418c..00000000
--- a/src/components/Icon/doc/style.scss
+++ /dev/null
@@ -1,17 +0,0 @@
-.item {
- width: 150px;
- word-break: break-all;
- .ant-typography {
- position: relative;
- }
- .ant-typography-copy {
- visibility: hidden;
- position: absolute;
- right: -20px;
- }
- &:hover {
- .ant-typography-copy {
- visibility: visible;
- }
- }
-}
diff --git a/src/components/Icon/style.module.scss b/src/components/Icon/style.module.scss
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/components/Image/README.md b/src/components/Image/README.md
index e0bc052e..d35991b3 100644
--- a/src/components/Image/README.md
+++ b/src/components/Image/README.md
@@ -2,29 +2,105 @@
### 概述
-用于展示一张图片,和img标签不同的是,可以展示一张普通图片,也可以通过id加载一张oss图片,在加载oss地址和图片数据的时候会显示loading状态
+Image 组件是一个增强的图片显示组件,支持两种加载方式:
+
+1. 通过 src 属性直接加载图片URL
+2. 通过 id 属性从 OSS 服务器加载图片
+
+组件特性:
+- 自动加载状态显示和错误处理
+- 支持 Avatar 头像模式,可显示默认性别图标
+- 支持自定义加载状态和错误状态组件
+- 完全兼容原生 img 标签的基本属性
+
+主要应用场景:
+- 用户头像展示
+- 商品图片展示
+- 文档预览
+- 需要加载状态的图片显示
### 示例
+#### 示例样式
+
+```scss
+/* Image 组件示例样式 */
+.product-card {
+ .ant-card-cover {
+ height: 180px;
+ overflow: hidden;
+ }
+}
+
+.user-avatar {
+ &:hover {
+ transform: scale(1.05);
+ transition: transform 0.3s;
+ }
+}
+
+.image-preview {
+ text-align: center;
+
+ img {
+ max-width: 100%;
+ border-radius: 4px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ }
+}
+```
+
#### 示例代码
-- 通过src加载一个普通图片
-- 通过src加载一个普通图片
-- _Image(@components/Image)
+- 基础图片加载
+- 通过src属性直接加载图片
+- _Image(@components/Image),antd(antd)
```jsx
-const {default: Image} = _Image;
+const { default: Image } = _Image;
+const { Space, Card, Typography } = antd;
+
+const { Text } = Typography;
+
const BaseExample = () => {
- return
;
+ return (
+
+
+
+
+
+
+
+
+
+
+ 1. Image 组件通过 src 属性直接加载图片URL。
+ 2. 支持本地图片和网络图片加载。
+ 3. 可以通过 style 属性设置图片大小。
+ 4. 自动处理加载状态和错误状态。
+
+
+
+ );
};
-render(
);
+render(
);
```
-- 通过id加载一个oss图片
-- 图片一加载成功,图片二加载中,图片三加载失败
+- OSS图片加载
+- 通过id从OSS服务器加载图片,展示加载中和失败状态
- _Image(@components/Image),global(@components/Global),antd(antd)
```jsx
@@ -63,8 +139,8 @@ render(
);
```
-- 显示一个头像
-- 显示图片头像和默认头像
+- 头像组件
+- 展示Image.Avatar头像组件的各种用法
- _Image(@components/Image),antd(antd)
```jsx
@@ -97,19 +173,393 @@ render(
);
```
+- 自定义状态组件
+- 自定义加载中和错误状态的显示组件
+- _Image(@components/Image),antd(antd),icon(@components/Icon)
+
+```jsx
+const { default: Image } = _Image;
+const { Space, Card, Spin, Alert } = antd;
+const { default: Icon } = icon;
+
+const CustomStatesExample = () => {
+ const customLoading = (
+
+
+
+ );
+
+ const customError = (
+
+
+
+ );
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+render(
);
+```
+
+- 图片交互
+- 展示图片点击事件和图片预览功能
+- _Image(@components/Image),antd(antd)
+
+```jsx
+const { default: Image } = _Image;
+const { Space, Card, Modal, Typography, Button } = antd;
+const { useState } = React;
+
+const { Text } = Typography;
+
+const ImageInteractionExample = () => {
+ const [previewVisible, setPreviewVisible] = useState(false);
+ const [previewImage, setPreviewImage] = useState('');
+
+ const handleImageClick = (src) => {
+ setPreviewImage(src);
+ setPreviewVisible(true);
+ };
+
+ const handlePreviewClose = () => {
+ setPreviewVisible(false);
+ };
+
+ return (
+
+
+
+ 点击图片查看大图:
+
+ handleImageClick('https://picsum.photos/seed/product1/600/600.jpg')}
+ alt="产品图片1"
+ />
+ handleImageClick('https://picsum.photos/seed/product2/600/600.jpg')}
+ alt="产品图片2"
+ />
+ handleImageClick('https://picsum.photos/seed/product3/600/600.jpg')}
+ alt="产品图片3"
+ />
+
+
+
+
+
+
+
+
console.log('点击了用户头像')}
+ style={{ cursor: 'pointer' }}
+ alt="用户头像"
+ />
+ 用户头像
+
+
+
console.log('点击了默认女性头像')}
+ style={{ cursor: 'pointer' }}
+ />
+ 默认女性头像
+
+
+
+
+
+
+ 1. Image 和 Image.Avatar 组件都支持 onClick 事件,可以添加交互功能。
+ 2. 结合 Modal 组件可以实现图片预览功能。
+ 3. 通过设置 cursor: 'pointer' 样式可以提示用户图片是可点击的。
+
+
+
+
+ 关闭
+
+ ]}
+ width={700}
+ onCancel={handlePreviewClose}
+ >
+
+

+
+
+
+ );
+};
+
+render(
);
+```
+
+- 真实业务场景
+- 用户信息卡片中的头像和商品列表中的图片展示
+- _Image(@components/Image),antd(antd)
+
+```jsx
+const { default: Image } = _Image;
+const { Space, Card, Typography, List, Avatar, Tag } = antd;
+
+const { Title, Text, Paragraph } = Typography;
+
+const RealScenarioExample = () => {
+ // 模拟用户数据
+ const users = [
+ {
+ id: 1,
+ name: '张三',
+ avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=zhangsan',
+ position: '前端开发工程师',
+ department: '技术部'
+ },
+ {
+ id: 2,
+ name: '李四',
+ avatar: '',
+ gender: 'male',
+ position: '产品经理',
+ department: '产品部'
+ },
+ {
+ id: 3,
+ name: '王五',
+ avatar: '',
+ gender: 'female',
+ position: 'UI设计师',
+ department: '设计部'
+ }
+ ];
+
+ // 模拟商品数据
+ const products = [
+ {
+ id: 1,
+ name: '高端笔记本电脑',
+ image: 'https://picsum.photos/seed/laptop/200/200.jpg',
+ price: 8999,
+ status: '在售'
+ },
+ {
+ id: 2,
+ name: '无线蓝牙耳机',
+ image: 'https://picsum.photos/seed/earphone/200/200.jpg',
+ price: 499,
+ status: '在售'
+ },
+ {
+ id: 3,
+ name: '智能手表',
+ image: 'https://picsum.photos/seed/watch/200/200.jpg',
+ price: 1299,
+ status: '缺货'
+ }
+ ];
+
+ return (
+
+
+ (
+
+
+ ) : (
+
+ )
+ }
+ title={
+
+ {user.name}
+
+ {user.department}
+
+
+ }
+ description={user.position}
+ />
+
+ )}
+ />
+
+
+
+ (
+
+
+ }
+ >
+
+
+ ¥{product.price}
+
+
+ {product.status}
+
+
+ }
+ />
+
+
+ )}
+ />
+
+
+