List组件(1)|青训营日记

83 阅读1分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 15天 拖延症患者终于开始完善List组件了,简单的不依赖其他组件的一个手写List组件。 今天完成了bordered属性、size属性、renderItem属性、header属性和footer属性

属性作用
sizelg/sm 默认为中等大小
borded有无框线
renderItem当使用 dataSource 时,可以用 renderItem 自定义渲染列表项
header表头
footer表底

比较难的是renderItem的逻辑,首先传入的是函数renderItem(item: string, index: number) => React.ReactNode

例如:

<List dataSource={data} renderItem = {(item) => (<ul>
        <img src = "./1.png" alt = "a picture" ></img>[ITEM] {item}</ul>)
        }></List>

我们将源数据中的每一项解析到renderItem中,然后再生成childrenContext渲染到页面上。

React.Fragment组件能够在不额外创建 DOM 元素的情况下,让 render()方法中返回多个元素。相当于空标签<></>。<></>和Fragment标签的区别:Fragment标签支持能接受键值或属性,可以遍历循环渲染元素

const renderInnerItem = (item: string, index: number) => {
        if (!renderItem) return null;
        return <React.Fragment>{renderItem(item, index)}</React.Fragment>;
      };
    let splitDataSource = dataSource;
    let childrenContent:ReactNode;
    if (splitDataSource.length > 0) {
        const items = splitDataSource.map((item: string, index: number) => renderInnerItem(item, index));
        childrenContent = <div className={`ai-list`}>{items}</div>
    }

list.tsx如下

import React, { ReactNode } from "react";
import "./style/list.scss"
import classNames from "classnames";
export type ListSize = "lg" | "md" | "sm";
interface ListProps{
    dataSource : any[];
    size ? : ListSize;
    header ? : ReactNode;
    footer ? : ReactNode;
    bordered ? : boolean;
    renderItem ?: (item: string, index: number) => React.ReactNode;
}
const List : React.FC<ListProps> = (props)=>{
    const {
        dataSource,
        size,
        header,
        footer,
        bordered,
        renderItem
    } = props;
    const renderInnerItem = (item: string, index: number) => {
        if (!renderItem) return null;
        return <React.Fragment>{renderItem(item, index)}</React.Fragment>;
      };
    let splitDataSource = dataSource;
    let childrenContent:ReactNode;
    if (splitDataSource.length > 0) {
        const items = splitDataSource.map((item: string, index: number) => renderInnerItem(item, index));
        childrenContent = <div className={`ai-list`}>{items}</div>
    }
    const classes = classNames("ai-listItem",  {
        [`ai-li-${size}`]: size, // size 参数存在时动态添加 `ai-li-${size}` 类 , size:padding
      });
    const listclasses = classNames("ai-list",  {
        [`ai-li-bordered-${String(bordered)}`] : bordered,
    }
    )    
    return(
        <>
        <div className={listclasses}>
            { footer && <div className= {classes}>{header}</div>}
                <>{
                !renderItem && 
                dataSource &&
                dataSource.map(data =>(
                <div className={classes}>
                    {data}
                </div>
                ) ) }  </>         
            { renderItem && <>{childrenContent}</>}
            {header && <div className={classes}>{footer}</div>}      
        </div></>
    )
}
export default List;

效果图如下:

image.png