Concis组件库封装——Table表格

简介: Concis组件库封装——Table表格封装记录

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

Concis表格组件提供了展开行、单选、多选、排序以及对大数据的处理方案,有虚拟列表、懒加载、分页,官方文档如下:
在这里插入图片描述
所提供的API能力如下:
在这里插入图片描述
在这里插入图片描述

虚拟列表主要使用了固定列高(15条数据 * 每条高度)+ 总列高(总数据 * 每条高度),在总高度滚动时根据滚动值不断改变显示的数据,而不改变DOM。
懒加载则是滚到底了,继续加载一部分数据。
分页比较常规,就不说了。

具体源码如下:

import React, {
   
    FC, useEffect, useCallback, useState, createRef, useMemo, memo } from 'react';
import {
   
    PlusOutlined, CaretUpOutlined, CaretDownOutlined } from '@ant-design/icons';
import {
   
    tableProps } from './interface';
import CheckBox from '../CheckBox';
import Pagination from '../Pagination';
import './style/index.module.less';

let sTop = 0;
const options = [10, 20, 30, 50];

const Table: FC<tableProps> = (props) => {
   
   
  const {
   
   
    titleParams,
    tableData,
    align,
    expandedRowRender,
    radio,
    checked,
    radioSelectCallback,
    checkedSelectCallback,
    avableSort,
    virtualized,
    largeDateShowNum = 10,
    lazyLoad,
    pagination,
    paginationAlign,
    pageSizeOption,
    changePNumCallback,
    changePSizeCallback,
    dropabled,
    dropCallback,
  } = props;

  const [doColumnData, setDoColumnData] = useState(titleParams); //表头数据
  const [doTableData, setDoTableData] = useState(tableData); //表数据
  const [radioRow, setRadioRow] = useState({
   
   }); //单选选中行
  const [checkedRow, setCheckedRow] = useState<Array<object>>([]); //单选选中行
  const [scrollTop, setScrollTop] = useState(0);
  const [pageSize, setPageSize] = useState(options[0]);
  const [pageNum, setPageNum] = useState(1);

  const scrollDom = createRef();

  useEffect(() => {
   
   
    let newDoTableData = [...doTableData];
    if (expandedRowRender) {
   
   
      //展开行处理
      newDoTableData.forEach((item: any) => {
   
   
        item.openLine = '';
      });
    }
    if (avableSort) {
   
   
      //排序处理
      setDoColumnData((old) => {
   
   
        old.forEach((item: any) => {
   
   
          if (Array.isArray(item.sorter)) {
   
   
            item.sorter = item.sorter.map((s: any) => {
   
   
              return {
   
   
                fn: s,
                sorted: false,
              };
            });
          }
        });
        return [...old];
      });
    }
    if (virtualized || lazyLoad) {
   
   
      newDoTableData = newDoTableData.slice(0, largeDateShowNum || 10);
    }
    if (pagination) {
   
   
      newDoTableData = newDoTableData.slice(0, pageSize);
    }
    setDoTableData(newDoTableData);
  }, []);

  const tableStyle = useCallback(
    (thData: any) => {
   
   
      //表头样式
      const styleResult = {
   
   
        width: 'auto',
      };
      if (thData?.width) {
   
   
        styleResult.width = `${
     
     thData.width}px`;
      }
      return styleResult;
    },
    [titleParams],
  );
  const openRow = (row: object, key: number): void => {
   
   
    //展开列表
    if (expandedRowRender) {
   
   
      expandedRowRender(row);
      const newTableData = [...doTableData];
      if (newTableData[key].openLine) {
   
   
        newTableData[key].openLine = '';
      } else {
   
   
        if (expandedRowRender(row)) {
   
   
        }
        newTableData[key]['openLine'] = expandedRowRender(row);
      }
      setDoTableData(newTableData);
    }
  };
  const radioSelectRow = (row: object): void => {
   
   
    //单选行
    setRadioRow(row);
    radioSelectCallback && radioSelectCallback(row);
  };
  const checkedSelectRow = (checked: boolean, row: object): void => {
   
   
    //多选单行
    setCheckedRow((old: any) => {
   
   
      if (checked) {
   
   
        old.push(row);
      } else {
   
   
        const delIndex = old.findIndex((s: object) => s == row);
        old.splice(delIndex, 1);
      }
      checkedSelectCallback && checkedSelectCallback(old);
      return [...old];
    });
  };
  const checkAll = (checked: boolean): void => {
   
   
    // 全部选中
    setCheckedRow((old: Array<object>) => {
   
   
      if (checked) {
   
   
        //全选
        old = doTableData;
      } else {
   
   
        //全不选
        old = [];
      }
      checkedSelectCallback && checkedSelectCallback(old);
      return [...old];
    });
  };
  const sortColumn = (index: number, row: any, sortType: number) => {
   
   
    //表格单列排序  -> 2为升序 3为降序
    const sortKey = row.dataIndex;
    const newTableData = [...doTableData];
    if (Array.isArray(row.sorter) && typeof row.sorter[0] == 'object') {
   
   
      //自定义排序
      newTableData.sort(row.sorter[sortType - 2].fn);
      setDoTableData(newTableData);
      setDoColumnData((old: Array<any>): Array<any> => {
   
   
        if (sortType == 2) {
   
   
          old[index].sorter[0].sorted = true;
          old[index].sorter[1].sorted = false;
        } else {
   
   
          old[index].sorter[0].sorted = false;
          old[index].sorter[1].sorted = true;
        }

        return [...old];
      });
    } else {
   
   
      //默认排序
      newTableData.sort((a, b) => {
   
   
        return sortType == 2 ? a[sortKey] - b[sortKey] : b[sortKey] - a[sortKey];
      });
      setDoTableData(newTableData);
      setDoColumnData((old) => {
   
   
        old[index].sorter = sortType;
        return [...old];
      });
    }
  };

  const renderContentTd = (rowData: object) => {
   
   
    //渲染正文行
    return Object.entries(rowData).map((value: any, key) => {
   
   
      if (value[0] !== 'openLine') {
   
   
        return (
          <td key={
   
   key} style={
   
   {
   
    textAlign: align ? (align as any) : 'left' }}>
            {
   
   value[1]}
          </td>
        );
      }
    });
  };
  const sortIconStyle = useCallback(
    (thRow: any, iconType: number) => {
   
   
      //表头排序按钮样式
      if (typeof thRow.sorter == 'number' || typeof thRow.sorter == 'boolean') {
   
   
        //默认排序
        if (iconType == 0) {
   
   
          //升序箭头
          return {
   
   
            color: thRow.sorter == 2 ? '#1890ff' : '#a9adb2',
          };
        } else {
   
   
          //降序箭头
          return {
   
   
            color: thRow.sorter == 3 ? '#1890ff' : '#a9adb2',
          };
        }
      } else {
   
   
        //自定义排序
        if (iconType == 0) {
   
   
          //升序箭头
          return {
   
   
            color: thRow.sorter[0].sorted ? '#1890ff' : '#a9adb2',
          };
        } else {
   
   
          //降序箭头
          return {
   
   
            color: thRow.sorter[1].sorted ? '#1890ff' : '#a9adb2',
          };
        }
      }
    },
    [titleParams, doColumnData],
  );
  const scrollTable = (e: any) => {
   
   
    if (virtualized) {
   
   
      //虚拟加载
      const top = (scrollDom.current as any).scrollTop;
      //滚到底,不继续滚
      if (
        (tableData.length + 2) *
          (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight -
          sTop <
          (largeDateShowNum + 2) *
            (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight &&
        top > sTop
      ) {
   
   
        return;
      }

      const listHeight = (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight || 40;
      sTop = top;
      setScrollTop(top);
      setDoTableData((old) => {
   
   
        const showNum = largeDateShowNum ? largeDateShowNum : 10;
        old = tableData.slice(Math.floor(top / listHeight), Math.floor(top / listHeight) + showNum);
        return [...old];
      });
    } else if (lazyLoad) {
   
   
      //懒加载
      if (
        e.nativeEvent.target.scrollHeight -
          e.nativeEvent.target.clientHeight -
          e.nativeEvent.target.scrollTop ==
        0
      ) {
   
   
        setDoTableData((old) => {
   
   
          old = [...old, ...tableData.slice(old.length + 1, old.length + 11)];
          return [...old];
        });
      }
    }
  };
  const changePageCallback = (pageNum: number) => {
   
   
    //页码改变回调
    setPageNum(pageNum);
    setDoTableData((old) => {
   
   
      old = tableData.slice((pageNum - 1) * pageSize, (pageNum - 1) * pageSize + pageSize);
      return [...old];
    });
    changePNumCallback &&
      changePNumCallback(
        pageNum,
        tableData.slice((pageNum - 1) * pageSize, (pageNum - 1) * pageSize + pageSize),
      );
  };
  const changePageSizeCallback = (pageSize: number) => {
   
   
    //页数改变回调
    setPageSize(pageSize);
    setDoTableData((old) => {
   
   
      old = tableData.slice(0, pageSize);
      return [...old];
    });
    changePSizeCallback && changePSizeCallback(pageSize, tableData.slice(0, pageSize));
  };
  const dargStart = (e: any, index: number) => {
   
   
    e.nativeEvent.dataTransfer.setData('dragKey', index);
  };

  const drop = (e: any, index: number) => {
   
   
    e.nativeEvent.preventDefault();
    const drapIndex = e.nativeEvent.dataTransfer.getData('dragKey');
    const dropIndex = index;
    setDoTableData((old) => {
   
   
      [old[drapIndex], old[dropIndex]] = [old[dropIndex], old[drapIndex]];
      dropCallback && dropCallback(old);
      return [...old];
    });
  };
  const dragOver = (e: any) => {
   
   
    e.nativeEvent.preventDefault();
  };
  const renderScrollList = useCallback(() => {
   
   
    //虚拟列表tr栏渲染
    return doTableData?.map((t, key) => {
   
   
      return (
        <>
          <tr key={
   
   key} className="victurl-scroll-tr">
            {
   
   
              //展开行
              expandedRowRender && (
                <td
                  style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}
                  onClick={
   
   () => openRow(t, key)}
                >
                  <PlusOutlined />
                </td>
              )
            }
            {
   
   
              //单选
              radio && (
                <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                  <input
                    className="radioBox"
                    type="radio"
                    checked={
   
   radioRow == t ? true : false}
                    onClick={
   
   () => radioSelectRow(t)}
                  ></input>
                </td>
              )
            }
            {
   
   
              //多选
              checked && (
                <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                  <CheckBox
                    checked={
   
   checkedRow.indexOf(t) == -1 ? false : true}
                    checkCallback={
   
   (check: boolean) => checkedSelectRow(check, t)}
                  >
                    {
   
   checkedRow.indexOf(t) == -1}
                  </CheckBox>
                </td>
              )
            }
            {
   
   renderContentTd(t)}
          </tr>
          {
   
   t.openLine && (
            <tr>
              <td
                style={
   
   {
   
    textAlign: (align as any) || 'left' }}
                colSpan={
   
   Object.keys(doTableData[0]).length + 1}
              >
                {
   
   t.openLine}
              </td>
            </tr>
          )}
        </>
      );
    });
  }, [doTableData, sTop, scrollTop, checkedRow, radioRow]);
  const tableContentRender = () => {
   
   
    //表正文渲染
    if (virtualized) {
   
   
      //虚拟列表
      return (
        <div
          style={
   
   {
   
   
            height:
              (tableData.length + 2) *
                (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight -
              sTop +
              'px',
            transform: `translateY(${
     
     sTop}px)`,
          }}
        >
          <thead>
            <tr>
              {
   
   (expandedRowRender || radio) && (
                <th style={
   
   {
   
    textAlign: (align as any) || 'left' }} />
              )}
              {
   
   checked && (
                <th style={
   
   {
   
    textAlign: (align as any) || 'left' }}>
                  <CheckBox
                    checked={
   
   checkedRow.length == doTableData.length}
                    checkCallback={
   
   (checked: boolean) => checkAll(checked)}
                  />
                </th>
              )}
              {
   
   doColumnData?.map((t, key) => {
   
   
                return (
                  <th key={
   
   key} style={
   
   tableStyle(t) as any} className="tableHead">
                    <div
                      style={
   
   {
   
   
                        display: 'flex',
                        justifyContent: align || 'flex-start',
                        alignItems: 'center',
                      }}
                    >
                      <span>{
   
   t.title}</span>
                      {
   
   t.sorter && avableSort && (
                        <div className="sort-icon">
                          <CaretUpOutlined
                            onClick={
   
   () => sortColumn(key, t, 2)}
                            style={
   
   sortIconStyle(t, 0)}
                          />
                          <CaretDownOutlined
                            onClick={
   
   () => sortColumn(key, t, 3)}
                            style={
   
   sortIconStyle(t, 1)}
                          />
                        </div>
                      )}
                    </div>
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>{
   
   renderScrollList()}</tbody>
        </div>
      );
    } else if (lazyLoad) {
   
   
      //懒加载
      return (
        <tbody>
          {
   
   doTableData?.map((t, key) => {
   
   
            return (
              <>
                <tr key={
   
   key}>
                  {
   
   
                    //展开行
                    expandedRowRender && (
                      <td
                        style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}
                        onClick={
   
   () => openRow(t, key)}
                      >
                        <PlusOutlined />
                      </td>
                    )
                  }
                  {
   
   
                    //单选
                    radio && (
                      <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                        <input
                          className="radioBox"
                          type="radio"
                          checked={
   
   radioRow == t ? true : false}
                          onClick={
   
   () => radioSelectRow(t)}
                        ></input>
                      </td>
                    )
                  }
                  {
   
   
                    //多选
                    checked && (
                      <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                        <CheckBox
                          checked={
   
   checkedRow.indexOf(t) == -1 ? false : true}
                          checkCallback={
   
   (check: boolean) => checkedSelectRow(check, t)}
                        >
                          {
   
   checkedRow.indexOf(t) == -1}
                        </CheckBox>
                      </td>
                    )
                  }
                  {
   
   renderContentTd(t)}
                </tr>
                {
   
   t.openLine && (
                  <tr>
                    <td
                      style={
   
   {
   
    textAlign: (align as any) || 'left' }}
                      colSpan={
   
   Object.keys(doTableData[0]).length + 1}
                    >
                      {
   
   t.openLine}
                    </td>
                  </tr>
                )}
              </>
            );
          })}
        </tbody>
      );
    } else if (pagination) {
   
   
      //分页渲染
      return (
        <tbody>
          {
   
   
            //常规表正文
            doTableData?.map((t, key) => {
   
   
              return (
                <>
                  <tr key={
   
   key}>
                    {
   
   
                      //展开行
                      expandedRowRender && (
                        <td
                          style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}
                          onClick={
   
   () => openRow(t, key)}
                        >
                          <PlusOutlined />
                        </td>
                      )
                    }
                    {
   
   
                      //单选
                      radio && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <input
                            className="radioBox"
                            type="radio"
                            checked={
   
   radioRow == t ? true : false}
                            onClick={
   
   () => radioSelectRow(t)}
                          ></input>
                        </td>
                      )
                    }
                    {
   
   
                      //多选
                      checked && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <CheckBox
                            checked={
   
   checkedRow.indexOf(t) == -1 ? false : true}
                            checkCallback={
   
   (check: boolean) => checkedSelectRow(check, t)}
                          >
                            {
   
   checkedRow.indexOf(t) == -1}
                          </CheckBox>
                        </td>
                      )
                    }
                    {
   
   renderContentTd(t)}
                  </tr>
                  {
   
   t.openLine && (
                    <tr>
                      <td
                        style={
   
   {
   
    textAlign: (align as any) || 'left' }}
                        colSpan={
   
   Object.keys(doTableData[0]).length + 1}
                      >
                        {
   
   t.openLine}
                      </td>
                    </tr>
                  )}
                </>
              );
            })
          }
        </tbody>
      );
    } else if (dropabled) {
   
   
      //拖拽表渲染
      return (
        <tbody>
          {
   
   
            //常规表正文
            doTableData?.map((t, key) => {
   
   
              return (
                <>
                  <tr
                    key={
   
   key}
                    style={
   
   {
   
    cursor: 'move' }}
                    draggable
                    onDragStart={
   
   (e) => dargStart(e, key)}
                    onDrop={
   
   (e) => drop(e, key)}
                    onDragOver={
   
   (e) => dragOver(e)}
                  >
                    {
   
   
                      //展开行
                      expandedRowRender && (
                        <td
                          style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}
                          onClick={
   
   () => openRow(t, key)}
                        >
                          <PlusOutlined />
                        </td>
                      )
                    }
                    {
   
   
                      //单选
                      radio && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <input
                            className="radioBox"
                            type="radio"
                            checked={
   
   radioRow == t ? true : false}
                            onClick={
   
   () => radioSelectRow(t)}
                          ></input>
                        </td>
                      )
                    }
                    {
   
   
                      //多选
                      checked && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <CheckBox
                            checked={
   
   checkedRow.indexOf(t) == -1 ? false : true}
                            checkCallback={
   
   (check: boolean) => checkedSelectRow(check, t)}
                          >
                            {
   
   checkedRow.indexOf(t) == -1}
                          </CheckBox>
                        </td>
                      )
                    }
                    {
   
   renderContentTd(t)}
                  </tr>
                  {
   
   t.openLine && (
                    <tr>
                      <td
                        style={
   
   {
   
    textAlign: (align as any) || 'left' }}
                        colSpan={
   
   Object.keys(doTableData[0]).length + 1}
                      >
                        {
   
   t.openLine}
                      </td>
                    </tr>
                  )}
                </>
              );
            })
          }
        </tbody>
      );
    } else {
   
   
      //常规表渲染
      return (
        <tbody>
          {
   
   
            //常规表正文
            doTableData?.map((t, key) => {
   
   
              return (
                <>
                  <tr key={
   
   key}>
                    {
   
   
                      //展开行
                      expandedRowRender && (
                        <td
                          style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}
                          onClick={
   
   () => openRow(t, key)}
                        >
                          <PlusOutlined />
                        </td>
                      )
                    }
                    {
   
   
                      //单选
                      radio && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <input
                            className="radioBox"
                            type="radio"
                            checked={
   
   radioRow == t ? true : false}
                            onClick={
   
   () => radioSelectRow(t)}
                          ></input>
                        </td>
                      )
                    }
                    {
   
   
                      //多选
                      checked && (
                        <td style={
   
   {
   
    textAlign: (align as any) || 'left', cursor: 'pointer' }}>
                          <CheckBox
                            checked={
   
   checkedRow.indexOf(t) == -1 ? false : true}
                            checkCallback={
   
   (check: boolean) => checkedSelectRow(check, t)}
                          >
                            {
   
   checkedRow.indexOf(t) == -1}
                          </CheckBox>
                        </td>
                      )
                    }
                    {
   
   renderContentTd(t)}
                  </tr>
                  {
   
   t.openLine && (
                    <tr>
                      <td
                        style={
   
   {
   
    textAlign: (align as any) || 'left' }}
                        colSpan={
   
   Object.keys(doTableData[0]).length + 1}
                      >
                        {
   
   t.openLine}
                      </td>
                    </tr>
                  )}
                </>
              );
            })
          }
        </tbody>
      );
    }
  };
  const paginationAlignStyle = useMemo(() => {
   
   
    let returnStyle = {
   
   };
    if (!paginationAlign) {
   
   
      returnStyle = {
   
   
        justifyContent: 'flex-start',
      };
    } else {
   
   
      switch (paginationAlign) {
   
   
        case 'left':
          returnStyle = {
   
   
            justifyContent: 'flex-start',
          };
          break;
        case 'center':
          returnStyle = {
   
   
            justifyContent: 'center',
          };
          break;
        case 'right':
          returnStyle = {
   
   
            justifyContent: 'flex-end',
          };
          break;
      }
    }
    return returnStyle;
  }, [paginationAlign]);
  return (
    <div
      className="table-container"
      style={
   
   
        virtualized || lazyLoad
          ? {
   
   
              height: `${
     
     
                (largeDateShowNum + 2) *
                (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight
              }px`,
            }
          : {
   
   }
      }
    >
      <div
        className="table"
        style={
   
   
          virtualized || lazyLoad
            ? {
   
   
                maxHeight: `${
     
     
                  (largeDateShowNum + 2) *
                  (document.querySelector('.victurl-scroll-tr') as any)?.offsetHeight
                }px`,
                overflow: 'scroll',
                position: 'absolute',
                top: '40px',
                left: '0',
              }
            : {
   
   }
        }
        onScroll={
   
   (e) => scrollTable(e)}
        ref={
   
   scrollDom as any}
      >
        <table>
          {
   
   
            //常规表格
            !virtualized && (
              <thead>
                <tr>
                  {
   
   (expandedRowRender || radio) && (
                    <th style={
   
   {
   
    textAlign: (align as any) || 'left' }} />
                  )}
                  {
   
   checked && (
                    <th style={
   
   {
   
    textAlign: (align as any) || 'left' }}>
                      <CheckBox
                        checked={
   
   checkedRow.length == doTableData.length}
                        checkCallback={
   
   (checked: boolean) => checkAll(checked)}
                      />
                    </th>
                  )}
                  {
   
   doColumnData.map((t, key) => {
   
   
                    return (
                      <th key={
   
   key} style={
   
   tableStyle(t) as any} className="tableHead">
                        <div
                          style={
   
   {
   
   
                            display: 'flex',
                            justifyContent: align || 'flex-start',
                            alignItems: 'center',
                          }}
                        >
                          <span>{
   
   t.title}</span>
                          {
   
   t.sorter && avableSort && (
                            <div className="sort-icon">
                              <CaretUpOutlined
                                onClick={
   
   () => sortColumn(key, t, 2)}
                                style={
   
   sortIconStyle(t, 0)}
                              />
                              <CaretDownOutlined
                                onClick={
   
   () => sortColumn(key, t, 3)}
                                style={
   
   sortIconStyle(t, 1)}
                              />
                            </div>
                          )}
                        </div>
                      </th>
                    );
                  })}
                </tr>
              </thead>
            )
          }
          {
   
   
            //表正文
            tableContentRender()
          }
        </table>
      </div>
      {
   
   pagination && (
        <div className="pagination" style={
   
   paginationAlignStyle}>
          <Pagination
            style={
   
   paginationAlignStyle}
            total={
   
   tableData.length}
            showSizeChanger
            pageSizeOptions={
   
   pageSizeOption || options}
            showJumpInput
            changePageSizeCallback={
   
   changePageSizeCallback}
            changePageCallback={
   
   changePageCallback}
          />
        </div>
      )}
    </div>
  );
};

export default memo(Table);

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

目录
相关文章
|
5月前
|
前端开发 数据格式
jeecgboot前端antd Table组件动态合并单元格
jeecgboot前端antd Table组件动态合并单元格
182 0
|
4月前
|
JavaScript 前端开发
Vue的高级表格组件库【vxe-table】
Vue的高级表格组件库【vxe-table】
109 0
|
8月前
|
数据处理 数据格式
hook项目实例之原始数据形成ant design table表格 2
hook项目实例之原始数据形成ant design table表格
41 0
|
8月前
|
数据格式
hook项目实例之原始数据形成ant design table表格
hook项目实例之原始数据形成ant design table表格
29 0
|
10月前
|
存储 API
【ElementUI】Table表格动态合并
【ElementUI】Table表格动态合并
144 0
|
JavaScript
VUE element-ui之table表格全局排序、调用后端接口排序功能
VUE element-ui之table表格全局排序、调用后端接口排序功能
1211 0
|
11月前
|
前端开发
Concis组件库封装——List列表
Concis组件库封装——List列表组件封装
74 1
|
11月前
|
前端开发 JavaScript
如何编写神奇的「插件机制」,优化基于 Antd Table 封装表格的混乱代码
最近在一个业务需求中,我通过在 Antd Table 提供的回调函数等机制中编写代码,实现了这些功能: ✨ 每个层级缩进指示线 ✨ 远程懒加载子节点 ✨ 每个层级支持分页
antd组件库封装74-subMenu下拉菜单编码-完美组件2
antd组件库封装74-subMenu下拉菜单编码-完美组件2
60 0
antd组件库封装74-subMenu下拉菜单编码-完美组件2
antd组件库封装42-样式解决方案分析
antd组件库封装42-样式解决方案分析
88 0
antd组件库封装42-样式解决方案分析