搜索类页面的封装实现, 使用react
npm install search-page- search-page
- Install
- Sreenshot
- Features
- Usage
- 一般性场景(简单使用)
- FiltersForm.tsx (使用 FormWrapper)
- HandwrittenFormDemo.tsx (完全自己手写)
- 配置用户侧自定义表头列宽度(Content.tsx)
- 关于聚焦刷新
- 典型场景
- 支持手动触发模式
- 如果同一个页面有多个 SearchPage 实例
- 支持指定存储数据使用的 history 对象
- forceUpdate 支持传递参数 forceUpdateArgs
- 如果需要定制化筛选条件, 请设置 FromWraper props -> defaultCustomFiltersConf
- 支持响应式布局, 请设置 FromWraper props -> theme, 或使用 FromWraper.FormItem props -> colProps
- License
> 搜索类页面的封装实现, 使用 react

``bash`
yarn add search-page
![[example/screenshot.png]](https://raw.githubusercontent.com/gmsoft-happyCoding/search-page/master/example/screenshot.png)
- [x] 自动记住页面状态,刷新或 history.back(),不会丢失页面状态
- [x] 数据请求自动节流,阈值 500ms
- [x] 自动显示 loading 状态, 为了避免闪烁默认 delay 500ms
- [x] 支持高级搜索,展开收起,收起时重置高级搜索部分的条件为默认值(filtersDefault)
- [x] 根据配置自动生成 form (目前只支持 input),非 input 组件或自定义组件使用 FormWrapper>)
- [x] 支持用户自定义筛选条件
- [x] 支持手动触发搜索
- [x] 支持响应式布局(default: { lg: 6, md: 8, sm: 12, xs: 24 })
- [x] 支持同一页面显示多个实例, 请传递不同的 storeKey
- [x] 如果不想"记住"状态, 请传递 noStore = true
- [x] 支持用户侧表头自定义宽度(不支持百分比设置,react-resizable 的属性缺陷,可以持续关注)
- [x] 加入聚焦自动刷新,页面数据能在页签聚焦时自动刷新
---
Demo.tsx
import React, { useRef, useCallback } from 'react';
import createSearchPage, { GetDataApi } from 'search-page';
import { Button } from 'antd';
import FiltersForm from './FiltersForm';
import Content from './Content';
const getDataApi: GetDataApi = async (filters, pagination) => {
await new Promise(resolve => setTimeout(resolve, 1000));
const result = await Promise.resolve({ data: { filters, pagination }, total: 100 });
return result;
};
const SearchPage = createSearchPage({
filtersDefault: { orgName: 'gmsoft' },
pageSize: 40,
noPagination: false,
getDataApi,
FiltersForm,
});
const Demo = () => {
const searchPageRef = useRef({ forceUpdate: () => undefined });
const forceUpdate = useCallback(() => {
searchPageRef.current.forceUpdate();
}, []);
return (
<div style={{ padding: 16 }}>
<SearchPage ref={searchPageRef}>{Content}</SearchPage>
<Button onClick={forceUpdate}>强制刷新</Button>
</div>
);
};
export default Demo;
Content.tsx
import React from 'react';
import styled from 'styled-components';
import { ContentProps } from 'search-page';
const Wrap = styled.div`
padding: 16px;
border: 2px solid purple;
background-color: #8000802e;
color: purple;
`;
const Content = ({ data, forceUpdate, loading, filters }: ContentProps) => (
<Wrap>
data: {JSON.stringify(data)}
<br />
filters: {JSON.stringify(filters)}
<a style={{ float: 'right' }} onClick={forceUpdate}>
强制刷新
</a>
</Wrap>
);
export default Content;
FiltersForm.tsx (使用 buildFiltersForm)
/**
* buildFiltersForm 目前只支持 input 类型
* 如果搜索条件复杂, 请使用FormWrapper
*/
import { buildFiltersForm, Fields } from 'search-page';
const fields: Fields = {
orgName: { type: 'input', label: '单位名称' },
orgCode1: { type: 'input', label: '组织机构代码 1' },
orgCode2: { type: 'input', label: '组织机构代码 2' },
orgCode3: { type: 'input', label: '组织机构代码 3' },
orgCode4: { type: 'input', label: '组织机构代码 4' },
};
export default buildFiltersForm(fields, {
// 可选,是否需要重置操作
needReset: true,
// 精简模式配置
simpleMode: {
enable: true,
count: 2,
// count 优先级高于 rows
// row: 1
},
});
---
#### FiltersForm.tsx (使用 FormWrapper)
`tsx
import React from 'react';
import { Form, Input, Select, Col } from 'antd';
import { FormWrapper, FiltersFormType } from 'search-page';
import { withRouter, RouteComponentProps } from 'react-router-dom';
const { Option } = Select;
// 包装容器,自定义栅格的时候使用
const { FormItem } = FormWrapper;
const FiltersForm: FiltersFormType
const {
form: { getFieldDecorator },
} = props;
return (
simpleMode={{ rows: 1 }}
resetRetainFiltersDefaultKeys={[]}
>
{/ 需要自定义栅格时请使用包装容器 /}
{getFieldDecorator('orgName')()}
{/ 可设置为响应式布局 /}
{getFieldDecorator('name1')(
)}
{/ 与Antd原有FormItem可以混用,原Form.Item占据默认栅格大小:8 /}
export default withRouter(FiltersForm);
`
---
#### HandwrittenFormDemo.tsx (完全自己手写)
`tsx
import React, { useCallback } from 'react';
import Form, { FormComponentProps } from 'antd/lib/form';
import { Row, Col, Input } from 'antd';
const FiltersForm = ({ form }: FormComponentProps) => {
const { resetFields, getFieldDecorator } = form;
const reset = useCallback(() => {
resetFields();
}, [resetFields]);
return (
export default FiltersForm;
`
注意事项:
1. Table 列配置只能使用 Confs 数组配置模式,不能使用 Jsx 模式
2. 列宽只能指定具体像素,不能使用百分比,插件实现问题
3. 列宽数据存储行为与 Filter 条件一致
4. dispatch、tableWidthConfs、storeKey 均为 SearchPage 内部属性,使用时可以直接透传 props 进行简写
5. 最右侧配置列的 width 请留空,不要写
`tsx
import React, { useEffect, useRef, useMemo, useCallback, useState } from 'react';
import styled from 'styled-components';
import { ContentProps, ResizeableTitle, getColumnConfs } from 'search-page';
import { Table, Button } from 'antd';
const Wrap = styled.div
padding: 16px;
border: 2px solid purple;;
const components = { header: { cell: ResizeableTitle } };
export default ({ data, forceUpdate, dispatch, tableWidthConfs, storeKey }: ContentProps) => {
const tableRef = useRef
const [columnConfs, setColumnConfs] = useState([
{
title: 'id',
key: 'id',
dataIndex: 'id',
width: 100,
},
{
// 所有配置列中,请保持有一个配置列的width不配置,否则会导致拖动自适应出现问题
title: 'operate',
key: 'operate',
dataIndex: 'operate',
},
]);
const renderColumnsConf = useMemo(
() =>
getColumnConfs({
columnConfs,
setConfs: setColumnConfs,
dispatch,
tableWidthConfs,
storeKey,
}),
[columnConfs, dispatch, storeKey, tableWidthConfs]
);
return (
ref={tableRef}
rowKey="id"
dataSource={data.data}
columns={renderColumnsConf}
pagination={false}
components={components}
size="small"
/>
{JSON.stringify(data)}
);
};
`
---
请在 createSearchPage 中指定 [autoRefresh] 即可,配置如下:
`ts`
export interface RefreshOpt {
/* 只要没有显示传递false,都默认true /
enable?: boolean;
/* 切换刷新的间隔时间,间隔时间内切换页签不会进行刷新 /
interval?: number;
}
#### 典型场景
`js`
// 页签聚焦自动刷新列表数据(此功能默认启用,默认自动请求间隔时间3000,间隔时间内重复聚焦不会再次触发刷新)
autoRefresh: { interval: 5000 },
// 关闭聚焦自动刷新(如果需要关闭则显示配置为false即可)
autoRefresh: { enable: false },
``
请在 createSearchPage 中指定 [searchMode]
``
请在 createSearchPage 中指定 [storeKey]
``
请在 createSearchPage 中指定 [storeHistory]
`ts
export interface PaginationI {
current: number;
pageSize: number;
}
export interface Filters {
[key: string]: any;
}
interface ForceUpdateArgs {
filters?: Filters;
pagination?: Partial
}
`
`ts`
/**
* 定制化筛选条件
*/
defaultCustomFiltersConf?: {
/**
* 定制配置存储在 localStorage 中 key
*/
storageKey: string;
/**
* 禁止定制的项
*/
notAllowCustomKeys?: string[];
/**
* 筛选配置面板label定制
*/
labels?: { [key: string]: string };
/**
* Popover.props.getPopupContainer
*/
getPopupContainer?: (triggerNode: HTMLElement) => HTMLElement;
/**
* Popover.props.overlayStyle
* @default { maxWidth: 450 }
*/
popoverOverlayStyle?: CSSProperties;
};
```
export interface ThemeI {
rowProps?: RowProps;
colProps?: ColProps;
}
> 详见 https://github.com/gmsoft-happyCoding/search-page/tree/master/example
> 如果你使用了 FromWraper.FormItem, 自定义了每个元素的栅格所占宽度,
> 请不要使用 simpleMode.rows(直接使用 simpleMode.count) 设置默认显示的元素数量,
> 因为这可能会导致默认显示的元素数量的计算错误
---
MIT © angular-moon