npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

search-page

v1.25.1

Published

搜索类页面的封装实现, 使用react

Downloads

20

Readme

search-page

搜索类页面的封装实现, 使用 react

NPM

Install

yarn add search-page

Sreenshot

[example/screenshot.png]

Features

  • [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] 加入聚焦自动刷新,页面数据能在页签聚焦时自动刷新

Usage

一般性场景(简单使用)

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;

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;

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)

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<RouteComponentProps<any>> = props => {
  const {
    form: { getFieldDecorator },
  } = props;

  return (
    <FormWrapper
      {...props}
      simpleMode={{ rows: 1 }}
      resetRetainFiltersDefaultKeys={[]}
    >
      {/* 需要自定义栅格时请使用包装容器 */}
      <FormItem span={8} label="orgName">
        {getFieldDecorator('orgName')(<Input placeholder="Please input your name" />)}
      </FormItem>
      {/* 可设置为响应式布局 */}
      <FormItem colProps={{ lg: 6, md: 8, sm: 12, xs: 24 }} label="name1">
        {getFieldDecorator('name1')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </FormItem>
      {/* 与Antd原有FormItem可以混用,原Form.Item占据默认栅格大小:8 */}
      <Form.Item label="name2">
        {getFieldDecorator('name2')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </Form.Item>
      <Form.Item label="name3">
        {getFieldDecorator('name3')(
          <Select>
            <Option value="1">选项一</Option>
            <Option value="2">选项二</Option>
          </Select>
        )}
      </Form.Item>
    </FormWrapper>
  );
};

export default withRouter(FiltersForm);

HandwrittenFormDemo.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 (
    <Form layout="vertical">
      <Row gutter={24}>
        <Col span={8}>
          <Form.Item label="单位名称">{getFieldDecorator('orgName')(<Input />)}</Form.Item>
        </Col>
        <Col span={16} style={{ textAlign: 'right' }}>
          <Form.Item label="&nbsp;">
            <a className="action" onClick={reset} role="button">
              重置筛选条件
            </a>
          </Form.Item>
        </Col>
      </Row>
    </Form>
  );
};

export default FiltersForm;

配置用户侧自定义表头列宽度(Content.tsx)

注意事项:

  1. Table 列配置只能使用 Confs 数组配置模式,不能使用 Jsx 模式
  2. 列宽只能指定具体像素,不能使用百分比,插件实现问题
  3. 列宽数据存储行为与 Filter 条件一致
  4. dispatch、tableWidthConfs、storeKey 均为 SearchPage 内部属性,使用时可以直接透传 props 进行简写
  5. 最右侧配置列的 width 请留空,不要写
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<any>();
  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 (
    <Wrap>
      <Table
        ref={tableRef}
        rowKey="id"
        dataSource={data.data}
        columns={renderColumnsConf}
        pagination={false}
        components={components}
        size="small"
      />
      {JSON.stringify(data)}
      <Button style={{ float: 'right' }} type="link" onClick={forceUpdate}>
        强制刷新
      </Button>
    </Wrap>
  );
};

关于聚焦刷新

请在 createSearchPage 中指定 [autoRefresh] 即可,配置如下:

export interface RefreshOpt {
  /** 只要没有显示传递false,都默认true */
  enable?: boolean;
  /** 切换刷新的间隔时间,间隔时间内切换页签不会进行刷新 */
  interval?: number;
}

典型场景

// 页签聚焦自动刷新列表数据(此功能默认启用,默认自动请求间隔时间3000,间隔时间内重复聚焦不会再次触发刷新)
autoRefresh: { interval: 5000 },
// 关闭聚焦自动刷新(如果需要关闭则显示配置为false即可)
autoRefresh: { enable: false },

支持手动触发模式

请在 createSearchPage 中指定 [searchMode]

如果同一个页面有多个 SearchPage 实例

请在 createSearchPage 中指定 [storeKey]

支持指定存储数据使用的 history 对象

请在 createSearchPage 中指定 [storeHistory]

forceUpdate 支持传递参数 forceUpdateArgs

export interface PaginationI {
  current: number;
  pageSize: number;
}

export interface Filters {
  [key: string]: any;
}

interface ForceUpdateArgs {
  filters?: Filters;
  pagination?: Partial<PaginationI>;
}

如果需要定制化筛选条件, 请设置 FromWraper props -> defaultCustomFiltersConf

 /**
   * 定制化筛选条件
   */
  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;
  };

支持响应式布局, 请设置 FromWraper props -> theme, 或使用 FromWraper.FormItem props -> colProps

export interface ThemeI {
  rowProps?: RowProps;
  colProps?: ColProps;
}

详见 https://github.com/gmsoft-happyCoding/search-page/tree/master/example

如果你使用了 FromWraper.FormItem, 自定义了每个元素的栅格所占宽度, 请不要使用 simpleMode.rows(直接使用 simpleMode.count) 设置默认显示的元素数量, 因为这可能会导致默认显示的元素数量的计算错误


License

MIT © angular-moon