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组件库线上地址吧~

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

目录
相关文章
|
8天前
|
数据挖掘 大数据 数据处理
python--列表list切分(超详细)
通过这些思维导图和分析说明表,您可以更直观地理解Python列表切分的概念、用法和实际应用。希望本文能帮助您更高效地使用Python进行数据处理和分析。
22 14
|
27天前
|
大数据 UED
「Mac畅玩鸿蒙与硬件16」鸿蒙UI组件篇6 - List 和 Grid 组件展示数据列表
List 和 Grid 是鸿蒙开发中的核心组件,用于展示动态数据。List 适合展示垂直或水平排列的数据列表,而 Grid 则适用于展示商品或图片的网格布局。本篇将展示如何封装组件,并通过按钮实现布局切换,提升界面的灵活性和用户体验。
61 9
「Mac畅玩鸿蒙与硬件16」鸿蒙UI组件篇6 - List 和 Grid 组件展示数据列表
|
10天前
|
数据挖掘 大数据 数据处理
python--列表list切分(超详细)
通过这些思维导图和分析说明表,您可以更直观地理解Python列表切分的概念、用法和实际应用。希望本文能帮助您更高效地使用Python进行数据处理和分析。
27 10
|
1月前
|
索引 Python
List(列表)
List(列表)。
39 4
|
2月前
|
测试技术 开发者 Python
在 Python 中创建列表时,应该写 `[]` 还是 `list()`?
在 Python 中,创建列表有两种方法:使用方括号 `[]` 和调用 `list()` 函数。虽然两者都能创建空列表,但 `[]` 更简洁、高效。性能测试显示,`[]` 的创建速度比 `list()` 快约一倍。此外,`list()` 可以接受一个可迭代对象作为参数并将其转换为列表,而 `[]` 则需要逐一列举元素。综上,`[]` 适合创建空列表,`list()` 适合转换可迭代对象。
在 Python 中创建列表时,应该写 `[]` 还是 `list()`?
|
1月前
|
Java
springboot将list封装成csv文件
springboot将list封装成csv文件
31 4
|
1月前
|
JavaScript 数据管理 虚拟化
ArkTS List组件基础:掌握列表渲染与动态数据管理
在HarmonyOS应用开发中,ArkTS的List组件是构建动态列表视图的核心。本文深入探讨了List组件的基础,包括数据展示、性能优化和用户交互,以及如何在实际开发中应用这些知识,提升开发效率和应用性能。通过定义数据源、渲染列表项和动态数据管理,结合虚拟化列表和条件渲染等技术,帮助开发者构建高效、响应式的用户界面。
196 2
|
2月前
|
NoSQL 关系型数据库 MySQL
Redis 列表(List)
10月更文挑战第16天
30 2
|
2月前
|
JavaScript
DOM 节点列表长度(Node List Length)
DOM 节点列表长度(Node List Length)
|
2月前
|
JavaScript
DOM 节点列表长度(Node List Length)
DOM 节点列表长度(Node List Length)