diff --git a/packages/biz/src/infiniteList/components/SearchCard.tsx b/packages/biz/src/CustomCard/components/commonCard/CommonCard.tsx similarity index 54% rename from packages/biz/src/infiniteList/components/SearchCard.tsx rename to packages/biz/src/CustomCard/components/commonCard/CommonCard.tsx index af4f9e2..a4feece 100644 --- a/packages/biz/src/infiniteList/components/SearchCard.tsx +++ b/packages/biz/src/CustomCard/components/commonCard/CommonCard.tsx @@ -2,14 +2,14 @@ * Created by jiangzhixiong on 2024/04/28 */ -import React, { forwardRef, useContext, useImperativeHandle } from 'react' +import React, { forwardRef, MouseEventHandler, ReactNode, useContext, useImperativeHandle } from 'react' import { ConfigProvider, EMPTY_BASE64 } from '@zhst/meta' import { Flex, Image } from 'antd'; import './index.less' const { ConfigContext } = ConfigProvider -export interface Idata { +export interface IData { id?: string | number; url?: string; sort?: number; @@ -17,24 +17,25 @@ export interface Idata { subtitle?: string; } -export interface SearchCardProps extends Idata { +export interface CommonCardProps extends IData { prefixCls?: string; - data?: Idata + data?: IData width?: string; height?: string; onCreateTxt?: string; - onCreate?: (data: any) => void; + onCreate?: () => void; onAddTxt?: string; onAdd?: (data: any) => void; onRemoveTxt?: string; onRemove?: (data: any) => void; - customOptionRender?: React.ReactNode + actions?: ReactNode[] + onItemClick?: (data: any, e: React.MouseEvent) => void; } -export interface SearchCardRefProps { +export interface CommonCardRefProps { } -const SearchCard = forwardRef((props, ref) => { +const CommonCard = forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, url, @@ -43,26 +44,29 @@ const SearchCard = forwardRef((props, ref) subtitle, sort, data, - onCreate, - onCreateTxt = '创建检索', - onAddTxt = '添加目标', - onRemoveTxt = '移除轨迹', - onAdd, - onRemove, - customOptionRender, + actions = [], width = '184px', - height = '100%' + height = '100%', + onItemClick } = props const { getPrefixCls } = useContext(ConfigContext) const componentName = getPrefixCls('biz-search-card', customizePrefixCls); - const stopBumble = (e: React.MouseEvent, fn?: ((data: Idata) => void), data?: Idata) => { - e.stopPropagation() - fn?.(data!) + const optionListRender = (_actions: ReactNode[]) => { + return _actions.map((action, i) => ( + // eslint-disable-next-line react/no-array-index-key +
  • + {action} + {i !== _actions.length - 1 && } +
  • + )) + } + + const handleItemClick = (e: React.MouseEvent, _data: IData | undefined) => { + onItemClick?.(data, e) } useImperativeHandle(ref, () => ({ - })) return ( @@ -72,9 +76,10 @@ const SearchCard = forwardRef((props, ref) width, height }} + onClick={e => handleItemClick(e, data)} >
    - {id || sort} + {sort || id} ((props, ref) preview={false} fallback={EMPTY_BASE64} /> - - {customOptionRender || ( - <> - stopBumble(e, onCreate, data)}>{onCreateTxt} - | - stopBumble(e, onAdd, data)}>{onAddTxt} - | - stopBumble(e, onRemove, data)}>{onRemoveTxt} - - )} - +
      + {optionListRender(actions)} +

    {title || data?.title}

    @@ -102,4 +99,4 @@ const SearchCard = forwardRef((props, ref) ) }) -export default SearchCard +export default CommonCard diff --git a/packages/biz/src/infiniteList/components/index.less b/packages/biz/src/CustomCard/components/commonCard/index.less similarity index 67% rename from packages/biz/src/infiniteList/components/index.less rename to packages/biz/src/CustomCard/components/commonCard/index.less index c9c413d..acd6da6 100644 --- a/packages/biz/src/infiniteList/components/index.less +++ b/packages/biz/src/CustomCard/components/commonCard/index.less @@ -1,18 +1,23 @@ .zhst-biz-search-card { + display: inline-block; border: 2px solid transparent; transition: .1s ease-in all; cursor: pointer; + overflow: hidden; &:hover { + transition: .5s ease all; border: 2px solid #09f; .zhst-biz-search-card-main-opt { display: flex; + align-items: center; } } &-main { position: relative; + overflow: hidden; &-num { position: absolute; @@ -32,11 +37,17 @@ &-img { width: 100%; - height: 240px; + overflow: hidden; + + &:hover { + transition: .5s ease-in all; + transform: scale(1.05); + } } &-opt { display: none; + margin: 0; position: absolute; padding: 6px 3px; left: 0; @@ -48,11 +59,28 @@ box-sizing: border-box; transition: .2s ease-in all; + li { + position: relative; + list-style: none; + flex: 1; + text-align: center; + } + + &-action-split { + position: absolute; + top: 50%; + right: 0; + width: 1px; + height: 80%; + transform: translateY(-50%); + background-color: #fff; + } + a { color: #fff; &:hover { - opacity: 0.9; + opacity: 0.88; } } } diff --git a/packages/biz/src/CustomCard/components/commonCard/index.tsx b/packages/biz/src/CustomCard/components/commonCard/index.tsx new file mode 100644 index 0000000..390b0af --- /dev/null +++ b/packages/biz/src/CustomCard/components/commonCard/index.tsx @@ -0,0 +1,5 @@ +import CommonCard from './CommonCard' + +export type { CommonCardProps, CommonCardRefProps } from './CommonCard' + +export default CommonCard diff --git a/packages/biz/src/CustomCard/demo/commonCard.tsx b/packages/biz/src/CustomCard/demo/commonCard.tsx new file mode 100644 index 0000000..8c48276 --- /dev/null +++ b/packages/biz/src/CustomCard/demo/commonCard.tsx @@ -0,0 +1,42 @@ +import React, { useEffect, useState } from 'react' +import { CommonCard } from '@zhst/biz' +import { uniqueId } from '@zhst/func' + +export default () => { + const [data, setData] = useState([]) + + useEffect(() => { + fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo') + .then((res) => res.json()) + .then((body) => { + let res = body.results.map((o, index) => { + return { + id: uniqueId(), + sort: index + 1, + title: o.name.first, + subtitle: o.name.last, + url: o.picture.large + } + }) + setData(res); + }) + }, []) + + return ( +
    + {data?.map(item => ( + 创建检索, + 创建布控, + 删除点位 + ]} + /> + ))} +
    + ) +} diff --git a/packages/biz/src/CustomCard/index.md b/packages/biz/src/CustomCard/index.md new file mode 100644 index 0000000..758b53b --- /dev/null +++ b/packages/biz/src/CustomCard/index.md @@ -0,0 +1,31 @@ +--- +category: Components +title: CustomCard 定制化卡片 +toc: content +group: + title: 数据展示 +--- + +定制化卡片 + +## 代码演示 + +基本卡片 + +## API + +### CommonCardProps + +| 参数 | 说明 | 类型 | 默认值 | 版本 | +| --- | --- | --- | --- | --- | +| data | 数据源 | IData[] | [] | - | +| prefixCls | 数据源 | string | [] | - | +| width | 宽度 | string | [] | - | +| height | 高度 | string | [] | - | +| onCreateTxt | 创建方法文字 | string | [] | - | +| onCreate | 创建方法 | () => void | [] | - | +| onAddTxt | 数据源 | string | [] | - | +| onAdd | 数据源 | () => void | [] | - | +| onRemoveTxt | 数据源 | string | [] | - | +| onRemove | 数据源 | () => void | [] | - | +| customOptionRender | 数据源 | React.ReactNode | - | - | diff --git a/packages/biz/src/CustomCard/index.tsx b/packages/biz/src/CustomCard/index.tsx new file mode 100644 index 0000000..67afe2c --- /dev/null +++ b/packages/biz/src/CustomCard/index.tsx @@ -0,0 +1,6 @@ +/** + * Created by jiangzhixiong on 2024/04/28 + */ + +export { default as CommonCard } from './components/commonCard' +export type { CommonCardProps, CommonCardRefProps } from './components/commonCard' diff --git a/packages/biz/src/index.tsx b/packages/biz/src/index.tsx index 1c67317..f9d89b3 100644 --- a/packages/biz/src/index.tsx +++ b/packages/biz/src/index.tsx @@ -9,6 +9,11 @@ export type { TreeTransferProps } from './treeTransfer' export { default as TreeTransferModal } from './treeTransferModal' export type { TreeTransferModalProps } from './treeTransferModal' export { default as WarningRecordCard } from './WarningRecordCard' +export { CommonCard } from './CustomCard' +export type { + CommonCardProps, + CommonCardRefProps +} from './CustomCard' export type { IRecord, WarningRecordCardProps } from './WarningRecordCard' export { default as OdModal } from './odModal' export type { ODModalProps } from './odModal' diff --git a/packages/biz/src/infiniteList/InfiniteList.tsx b/packages/biz/src/infiniteList/InfiniteList.tsx index b8f5bba..53c6097 100644 --- a/packages/biz/src/infiniteList/InfiniteList.tsx +++ b/packages/biz/src/infiniteList/InfiniteList.tsx @@ -2,24 +2,30 @@ * Created by jiangzhixiong */ -import React, { forwardRef, ReactNode, useContext, useImperativeHandle, useRef } from 'react' +import React, { forwardRef, ReactNode, useContext, useEffect, useImperativeHandle, useRef } from 'react' import { ConfigProvider } from '@zhst/meta'; -import { Divider, Flex } from 'antd'; import classNames from 'classnames'; import InfiniteScroll from 'react-infinite-scroll-component'; -import { SearchCard, SearchCardProps } from './components'; +import { Spin, SpinProps } from 'antd'; +import { useSize } from '@zhst/hooks'; import './index.less' -import { Idata } from './components/SearchCard'; const { ConfigContext } = ConfigProvider -export interface InfiniteListProps { +export interface IData { + key: string; + title: string; + index?: number; + [k: string]: any; +} + +export interface InfiniteListProps extends React.HtmlHTMLAttributes { type?: 'custom' | 'auto' prefixCls?: string; height?: number; - itemRender?: (data?: any) => React.ReactNode + itemRender?: (data?: IData, index?: number) => React.ReactNode loading?: boolean; // - data: Idata[]; + data: IData[]; targetId?: string; // 滚动列表 ID loadMore?: (data?: any) => any; params?: { @@ -28,101 +34,79 @@ export interface InfiniteListProps { hasMore: boolean; endMessage?: ReactNode loadingMessage?: ReactNode - onItemClick?: (data: any) => void; - searchCardProps?: SearchCardProps + loadingProps?: SpinProps } export interface InfiniteListRefProps { - + scrollViewSize?: { width: number; height: number } + listSize?: { width: number; height: number } } const InfiniteList = forwardRef((props, ref) => { const { prefixCls: customizePrefixCls, - height, + height = 600, + loading, type = 'auto', loadingMessage =

    加载中...

    , targetId = 'scrollableDiv', - itemRender, + itemRender = (data) =>
    {data?.title}
    , hasMore, - onItemClick, loadMore, data = [], - endMessage = 没有更多数据了...🤐, - searchCardProps + endMessage =
    没有更多数据了...🤐
    , + style, + loadingProps, + className } = props const { getPrefixCls } = useContext(ConfigContext); const componentName = getPrefixCls('biz-infinite-list', customizePrefixCls); const listRef = useRef(null); + const scrollRef = useRef(null); + const scrollViewSize = useSize(listRef.current) || { width: 0, height: 0 }; // 无限滚动视窗大小 + // @ts-ignore + const listSize = useSize(scrollRef.current?._infScroll) || { width: 0, height: 0 } // 无限滚动列表大小 + useEffect(() => { + // 当数据不够一屏时继续加载 + if (listSize.height < scrollViewSize.height) { + loadMore?.() + } + }, [listSize.height]) useImperativeHandle(ref, () => ({ - + scrollViewSize, + listSize })) return ( -
    - {/* {loading ? ( -

    加载中...

    - ) : ( - - {data?.list?.map((item) => ( - itemRender?.(item) || ( -
    - -
    - ) - ))} -
    - )} */} - {}} - hasMore={hasMore} - loader={loadingMessage} - endMessage={endMessage} - scrollableTarget={targetId} + +
    - + {}} + hasMore={hasMore} + loader={loadingMessage} + endMessage={endMessage} + scrollableTarget={targetId} + > {data?.map((item, idx) => ( - itemRender?.(item) || ( -
    { - onItemClick?.(item) - }} - > - -
    - ) + itemRender?.({ ...item, index: idx}) ))} -
    - - {/*
    - {!noMore && ( - - )} - - {noMore && 没有更多数据了} -
    */} -
    +
    +
    + ) }) diff --git a/packages/biz/src/infiniteList/components/index.tsx b/packages/biz/src/infiniteList/components/index.tsx deleted file mode 100644 index a096de9..0000000 --- a/packages/biz/src/infiniteList/components/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -/** - * Created by jiangzhixiong on 2024/04/28 - */ - -export { default as SearchCard } from './SearchCard' -export type { SearchCardProps, SearchCardRefProps } from './SearchCard' diff --git a/packages/biz/src/infiniteList/demo/basic.tsx b/packages/biz/src/infiniteList/demo/basic.tsx index 1abb269..005efe6 100644 --- a/packages/biz/src/infiniteList/demo/basic.tsx +++ b/packages/biz/src/infiniteList/demo/basic.tsx @@ -1,5 +1,6 @@ import React, { useEffect, useState } from 'react' -import { InfiniteList } from '@zhst/biz' +import { InfiniteList, CommonCard } from '@zhst/biz' +import { uniqueId } from '@zhst/func' export default () => { const [data, setData] = useState([]) @@ -13,8 +14,10 @@ export default () => { fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo') .then((res) => res.json()) .then((body) => { - let res = body.results.map(o => { + let res = body.results.map((o, index) => { return { + id: uniqueId(), + sort: index + 1, title: o.name.first, subtitle: o.name.last, url: o.picture.large @@ -36,14 +39,23 @@ export default () => { console.log('item点击:', _data)} - searchCardProps={{ - onAdd: (_data) => console.log('新增', _data), - onCreate: (_data) => console.log('创建', _data), - onRemove: (_data) => console.log('删除', _data), + itemRender={(item) => { + return ( + 创建检索, + 创建布控, + 删除点位 + ]} + /> + ) }} /> ) diff --git a/packages/biz/src/infiniteList/demo/custom.tsx b/packages/biz/src/infiniteList/demo/custom.tsx index 38310b7..ca698d7 100644 --- a/packages/biz/src/infiniteList/demo/custom.tsx +++ b/packages/biz/src/infiniteList/demo/custom.tsx @@ -3,11 +3,11 @@ import { InfiniteList } from '@zhst/biz' import { Button, Input, Space } from 'antd' export default () => { - const [data, setData] = useState([]) + const [data, setData] = useState([]) const [loading, setLoading] = useState(false) const [params, setParams] = useState({}) - const loadMoreData = (params?: { name: string; age?: number; sex: string; tel: number }) => { + const loadMoreData = (params?: any) => { if (loading) { return; } @@ -15,7 +15,7 @@ export default () => { fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo') .then((res) => res.json()) .then((body) => { - let res = body.results.map(o => { + let res = body.results.map((o: { name: { first: any; last: any }; picture: { large: any } }) => { return { title: o.name.first, subtitle: o.name.last, @@ -35,7 +35,7 @@ export default () => { }, []); return ( - + setParams(pre => ({ ...pre, name: e.target.value }))} style={{ width: '120px' }} /> setParams(pre => ({ ...pre, age: e.target.value }))} style={{ width: '120px' }} /> @@ -49,9 +49,7 @@ export default () => { height={300} hasMore={data.length < 100} data={data} - type="custom" loadingMessage={} - onItemClick={data => console.log('item点击:', data)} /> ) diff --git a/packages/biz/src/infiniteList/index.md b/packages/biz/src/infiniteList/index.md index 186315c..2135cf3 100644 --- a/packages/biz/src/infiniteList/index.md +++ b/packages/biz/src/infiniteList/index.md @@ -18,21 +18,20 @@ group: | 参数 | 说明 | 类型 | 默认值 | 版本 | | --- | --- | --- | --- | --- | -| data | 数据源 | Idata[] | [] | - | +| data | 数据源 | IData[] | [] | - | +| height | 无限滚动列表可视区高度 | number | 600 | - | | loading | 数据源 | Array[] | [] | - | -| data | 数据源 | Array[] | [] | - | -| data | 数据源 | Array[] | [] | - | -| data | 数据源 | Array[] | [] | - | -| data | 数据源 | Array[] | [] | - | -| data | 数据源 | Array[] | [] | - | +| dataLength | 数据数量 | number | [] | - | +| next | 下一页方法 | function | () => {} | - | +| hasMore | 是否还有更多 | boolean | false | - | +| loadingProps | 参考 antd-spin | spinProps | [] | - | +| itemRender | 自定义渲染项 | (IData) => ReactNode | - | - | -## Idata +## 设计思路 -```js -interface Idata { - id?: string | number; - url?: string; // 链接 - title?: string; // 标题 - subtitle?: string; // 副标题 -} -``` +无限滚动,同时支持: + +1. 自动、主动加载更多 +2. 一屏没加载完,继续加载,直到填满屏幕: + - 需要第二次加载的内容是否为空,为空则停止加载 + - 通过整体的page-height 和 浏览器可视区域 diff --git a/packages/biz/src/infiniteList/type.ts b/packages/biz/src/infiniteList/type.ts new file mode 100644 index 0000000..e69de29