Concis组件库封装——List列表

简介: Concis组件库封装——List列表组件封装

您好,如果喜欢我的文章,可以关注我的公众号「量子前端」,将不定期关注推送前端好文~

列表组件的封装其实和Table有一定的相似,都是数据一列一列展示,因此列表组件也用到了懒加载和虚拟列表对大数据量时提供了解决方案。

组件库文档:
在这里插入图片描述
List.tsx:

import React, {
   
    createContext, useMemo, useState, useEffect, useRef } from 'react';
import {
   
    listProps, listHeaderStyle, listContentStyle } from './interface';
import Item from './item';
import './style/list.module.less';

export const ctx = createContext<any>({
   
   } as any); //顶层通信装置
const List = (props: listProps) => {
   
   
  const {
   
   
    style = {
   
   },
    dataSource,
    render,
    header,
    size = 'default',
    lazyLoad = false,
    defaultShowNum = 5,
    virtualListProps,
    virtualShowNum = 5,
  } = props;

  const contextProps = {
   
   
    size,
  };
  const [formatDataSrouce, setFormatDataSource] = useState([...dataSource]); //处理过的数据源
  const [scrollTop, setScrollTop] = useState(0);
  const listItemHeight = useRef<any>(null);

  const listContentRef = useRef<any>(null);
  const victurlListContentRef = useRef<any>(null);

  useEffect(() => {
   
   
    if (lazyLoad && defaultShowNum) {
   
   
      setFormatDataSource((old) => {
   
   
        old = dataSource.slice(0, defaultShowNum);
        return [...old];
      });
    } else if (virtualListProps) {
   
   
      let rowHeight = document.querySelector('.list-item')?.clientHeight as any;
      switch (size) {
   
   
        case 'default':
          rowHeight += 26;
          break;
        case 'small':
          rowHeight += 18;
          break;
        case 'large':
          rowHeight += 34;
          break;
      }
      listItemHeight.current = rowHeight;
      setFormatDataSource((old) => {
   
   
        old = dataSource.slice(0, virtualShowNum + 2);
        return [...old];
      });
    }
  }, []);

  const listHeaderStyle = useMemo(() => {
   
   
    //头部样式
    const defaultStyles: listHeaderStyle = {
   
   };
    switch (size) {
   
   
      case 'default':
        defaultStyles.padding = '12px 20px';
        break;
      case 'small':
        defaultStyles.padding = '8px 20px';
        break;
      case 'large':
        defaultStyles.padding = '16px 20px';
        break;
    }
    return defaultStyles;
  }, [size]);

  const listStyle = useMemo(() => {
   
   
    //表整体样式
    return style;
  }, [style]);
  const listContentStyle = useMemo(() => {
   
   
    //表正文样式
    const returnStyle: listContentStyle = {
   
   };
    if (lazyLoad && defaultShowNum) {
   
   
      returnStyle.height = '400px';
      returnStyle.overflow = 'scroll';
    }
    return returnStyle;
  }, [lazyLoad, defaultShowNum]);
  const scrollList = () => {
   
   
    const {
   
    scrollHeight, clientHeight, scrollTop } = listContentRef.current as any;
    const bottomTran = scrollHeight - clientHeight - scrollTop; //距离底部距离
    if (bottomTran === 0) {
   
   
      setTimeout(() => {
   
   
        setFormatDataSource((old) => {
   
   
          old = dataSource.slice(0, old.length + defaultShowNum);
          return [...old];
        });
      }, 500);
    }
  };
  const victurlScroll = () => {
   
   
    const startIndex = Math.floor(victurlListContentRef.current.scrollTop / listItemHeight.current);
    setScrollTop(victurlListContentRef.current.scrollTop);
    setFormatDataSource((old) => {
   
   
      old = dataSource.slice(startIndex, startIndex + virtualShowNum + 2);
      return [...old];
    });
  };

  return (
    <ctx.Provider value={
   
   contextProps}>
      <div className="rList" style={
   
   listStyle}>
        <div className="list-header" style={
   
   listHeaderStyle}>
          {
   
   header}
        </div>
        {
   
   virtualListProps ? (
          <div
            className="victurl-list-content"
            style={
   
   {
   
    height: virtualShowNum * listItemHeight.current + 'px' }}
            ref={
   
   victurlListContentRef}
            onScroll={
   
   victurlScroll}
          >
            <div
              className="victurl-relly-content"
              style={
   
   {
   
   
                height: dataSource.length * listItemHeight.current - scrollTop + 'px',
                transform: `translate(0, ${
     
     scrollTop}px)`,
              }}
            >
              {
   
   formatDataSrouce.map(render)}
            </div>
          </div>
        ) : (
          <div
            className="list-content"
            style={
   
   listContentStyle}
            ref={
   
   listContentRef}
            onScroll={
   
   scrollList}
          >
            {
   
   formatDataSrouce.map(render)}
          </div>
        )}
      </div>
    </ctx.Provider>
  );
};

interface ForwardRefListType
  extends React.ForwardRefExoticComponent<
    React.PropsWithoutRef<listProps> & React.RefAttributes<HTMLDivElement>
  > {
   
   
  <T = any>(
    props: React.PropsWithChildren<listProps<T>> & {
   
   
      ref?: React.Ref<HTMLDivElement>;
    },
  ): React.ReactElement;
  Item: typeof Item;
}

const ListComponent = React.forwardRef<HTMLDivElement, listProps>(List) as ForwardRefListType;
ListComponent.Item = Item;
ListComponent.displayName = 'List';

export default ListComponent;

Item.tsx:

import React, {
   
    FC, memo, useMemo, useContext } from 'react';
import {
   
    listItemProps } from './interface';
import {
   
    ctx } from './index';
import './style/item.module.less';

const Item: FC<listItemProps> = (props) => {
   
   
  const {
   
    children, style = {
   
   } } = props;
  const {
   
    size } = useContext(ctx);

  const listItemStyle = useMemo(() => {
   
   
    const defaultStyles = style;
    switch (size) {
   
   
      case 'default':
        defaultStyles.padding = '13px 20px';
        break;
      case 'small':
        defaultStyles.padding = '9px 20px';
        break;
      case 'large':
        defaultStyles.padding = '17px 20px';
        break;
    }
    return defaultStyles;
  }, [size]);
  return (
    <div className="list-item" style={
   
   listItemStyle}>
      {
   
   children}
    </div>
  );
};

export default memo(Item);

最后留一下React-View-UI组件库线上地址吧~

开源不易,欢迎学习和体验,喜欢请多多支持,有问题请留言。

目录
相关文章
|
5天前
|
JavaScript
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的长度,即节点数量。通过遍历这个属性,可以访问和处理所有节点。例如,示例代码加载&quot;books.xml&quot;,获取所有&quot;title&quot;节点,并依次输出它们的第一个子节点的值。
|
1月前
|
XML JavaScript 数据格式
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的元素数量。在示例中,代码加载&quot;books.xml&quot;,然后通过`getElementsByTagName(&quot;title&quot;)`获取所有标题节点。使用`for`循环遍历这些节点,输出每个标题的文本内容。这个例子展示了如何交互式地处理XML文档中的特定标签。
|
9天前
|
JavaScript
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的元素数量。在示例中,代码加载&quot;books.xml&quot;,然后通过`getElementsByTagName(&quot;title&quot;)`获取所有标题节点。使用`for`循环遍历这些节点,输出每个标题的文本内容。
|
1月前
|
JavaScript
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的元素数量。通过遍历这个属性,如`for (i=0;i&lt;x.length;i++)`,可以访问和处理每个节点。在示例中,代码加载&quot;books.xml&quot;,然后获取所有&quot;title&quot;标签,并打印它们的子节点值。
|
16天前
|
前端开发 开发者
CSS列表属性:list-style系列属性详解
CSS列表属性:list-style系列属性详解
116 40
|
3天前
|
存储 缓存 Python
Python中的列表(List)和元组(Tuple)是两种重要的数据结构
【7月更文挑战第12天】Python中的列表(List)和元组(Tuple)是两种重要的数据结构
6 1
|
14天前
|
索引 Python
List(列表)
【7月更文挑战第1天】List(列表)。
13 1
|
22天前
|
JavaScript
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的元素数量。通过它,可以迭代列表,如示例所示:加载&quot;books.xml&quot;,然后获取所有&quot;title&quot;节点。循环`x.length`,打印每个标题节点的第一个子节点的值。
|
27天前
|
JavaScript
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的元素数量。通过遍历这个属性,如`for (i=0; i&lt;x.length; i++)`,可以访问和处理每个节点。在示例中,代码加载&quot;books.xml&quot;,然后获取所有&quot;title&quot;节点,并打印它们的第一个子节点的值。
|
29天前
|
XML JavaScript 数据格式
DOM 节点列表长度(Node List Length)
`length`属性用于获取DOM节点列表的长度,即节点数量。通过它可遍历列表,如`for(i=0; i&lt;x.length; i++)`循环访问每个`title`节点,并输出其内容。示例展示了从&quot;books.xml&quot;加载XML后,获取并打印所有标题节点的值。