加入收藏 | 设为首页 | 会员中心 | 我要投稿 厦门网 (https://www.xiamenwang.cn/)- 数据采集、建站、AI开发硬件、专属主机、云硬盘!
当前位置: 首页 > 教程 > 正文

如何在React中确保标题始终居中

发布时间:2023-07-12 10:54:04 所属栏目:教程 来源:转载
导读:   给大家分享一下react如何实现表头固定的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,
  给大家分享一下react如何实现表头固定的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。
 
  react实现表头固定的方法:1、通过Ant Design的Table组件实现表格固定表头;2、使用“rc-table”实现移动端表格表头固定;3、通过监听div的onscroll事件,改变div的scrollLeft属性。
 
  React表格固定表头/锁定列
 
  Ant Design的Table组件挺好用,固定表头及锁定列的功能不在话下,但Ant Design Mobile没有Table组件。移动端要实现表格固定表头及锁定列的功能应该可以使用rc-table,当然也可以自己写一个。
 
  通过分析AntD的Table,可以看出固定表头的表格是由上下两个<table>标签组成的,它们分别嵌套在div内,上面的是表头,只包含<thead>,下边是表格内容,只包含<tbody>。应该是通过监听下面div的onscroll事件,改变上面div的scrollLeft属性,这样在水平滚动表格时,表头也会同步滚动。固定列是通过设置th及td的CSS属性position为sticky并且设置left或right为0实现,同时设置z-index,让锁定的列始终显示在上方。
 
  原理整明白了,写代码就比较容易了。
 
 
  components/ScrollableTable/interface.tsx
 
  import * as React from 'react';
 
  export declare type AlignType = 'left' | 'center' | 'right';
 
  export interface ColumnType {
 
    align?: AlignType;
 
    className?: string;
 
    dataKey?: string;
 
    fixed?: boolean;
 
    title?: React.ReactNode;
 
    width?: number;
 
    render?: (value: any, record: any, index: number) => React.ReactNode;
 
  }
 
  export interface TableProps {
 
    className?: string;
 
    style?: React.CSSProperties;
 
    columns?: ColumnType[];
 
    dataSource?: any[];
 
    width?: number;
 
    height?: number;
 
  }
 
  components/ScrollableTable/index.tsx
 
  import React, { FunctionComponent, useRef } from 'react';
 
  import { TableProps, ColumnType } from './interface';
 
  import './index.less';
 
  const ScrollableTable: FunctionComponent<any> = (props: TableProps) => {
 
    const style: React.CSSProperties = props.style || {};
 
    const maxHeight: string = props.width ? (props.height + 'px') : 'unset';
 
    const columns: ColumnType[] = props.columns || [];
 
    const dataSource: any[] = props.dataSource || [];
 
    let maxWidth: number = 0;
 
    if (props.width) style.width = props.width;
 
    if (columns.length === 0) {
 
      columns.push({
 
        dataKey: 'key'
 
      });
 
    }
 
    columns.forEach((column: ColumnType) => {
 
      const width: number = column.width || 50;
 
      maxWidth += width;
 
    });
 
    const fixedColumns: number[][] = getFixedColumns(columns);
 
    const leftFixedColumns: number[] = fixedColumns[0];
 
    const rightFixedColumns: number[] = fixedColumns[1];
 
    const tableBody: any = useRef();
 
    const handleScroll = (target: any) => {
 
      const scrollLeft: number = target.scrollLeft;
 
      const tableHeaders: any = target.parentElement.getElementsByClassName('st-table-header');
 
      if (tableHeaders.length > 0) {
 
        tableHeaders[0].scrollLeft = scrollLeft;
 
      }
 
    };
 
    return (
 
      <div
 
        className={classNames('st-table-container', props.className)}
 
        style={style}
 
      >
 
        <div className="st-table-header">
 
          <table>
 
            <colgroup>
 
              {
 
                renderCols(columns)
 
              }
 
            </colgroup>
 
            <thead className="st-table-thead">
 
              <tr>
 
                {
 
                  columns.map((column: ColumnType, index: number) => {
 
                    const align: any = column.align || undefined;
 
                    const title: React.ReactNode = column.title || '';
 
                    const fixed: string = leftFixedColumns.includes(index) ? 'left' : (rightFixedColumns.includes(index) ? 'right' : '');
 
                    const fixedClassName: string = fixed ? ('st-table-cell-fix-' + fixed) : '';
 
                    return (
 
                      <th
 
                        key={index}
 
                        className={classNames('st-table-cell', fixedClassName, column.className)}
 
                        style={{textAlign: align}}
 
                      >
 
                        {title}
 
                      </th>
 
                    );
 
                  })
 
                }
 
              </tr>
 
            </thead>
 
          </table>
 
        </div>
 
        <div
 
          ref={tableBody}
 
          className="st-table-body"
 
          style={{maxHeight: maxHeight}}
 
          onScroll={(e: any) => handleScroll(e.currentTarget)}
 
        >
 
          <table style={{width: maxWidth, minWidth: '100%'}}>
 
            <colgroup>
 
                {
 
                  renderCols(columns)
 
                }
 
              </colgroup>
 
              <tbody className="st-table-tbody">
 
                {
 
                  dataSource.map((record: any, index: number) => (
 
                    <tr key={index} className="st-table-row">
 
                      {
 
                        renderCells(columns, leftFixedColumns, rightFixedColumns, record, index)
 
                      }
 
                    </tr>
 
                  ))
 
                }
 
              </tbody>
 
          </table>
 
        </div>
 
      </div>
 
    );
 
  };
 
  function classNames(...names: (string | undefined)[]) {
 
    const currentNames: string[] = [];
 
    names.forEach((name: (string | undefined)) => {
 
      if (name) currentNames.push(name);
 
    });
 
    return currentNames.join(' ');
 
  }
 
  function getFixedColumns(columns: ColumnType[]) {
 
    const total: number = columns.length;
 
    const leftFixedColumns: number[] = [];
 
    const rightFixedColumns: number[] = [];
 
    if (columns[0].fixed) {
 
      for (let i = 0; i < total; i++) {
 
        if (columns[i].fixed) {
 
          leftFixedColumns.push(i);
 
        } else {
 
          break;
 
        }
 
      }
 
    }
 
    if (columns[total - 1].fixed) {
 
      for (let i = total - 1; i >= 0; i--) {
 
        if (columns[i].fixed) {
 
          if (!leftFixedColumns.includes(i)) rightFixedColumns.push(i);
 
        } else {
 
          break;
 
        }
 
      }
 
    }
 
    return [leftFixedColumns, rightFixedColumns];
 
  }
 
  function renderCols(columns: ColumnType[]) {
 
    return columns.map((column: ColumnType, index: number) => {
 
      const width: number = column.width || 50;
 
      return (
 
        <col
 
          key={index}
 
          style={{width: width, minWidth: width}}
 
        />
 
      );
 
    });
 
  }
 
  function renderCells(columns: ColumnType[], leftFixedColumns: number[], rightFixedColumns: number[], record: any, index: number) {
 
    return columns.map((column: ColumnType, index: number) => {
 
      const align: any = column.align || undefined;
 
      const fixed: string = leftFixedColumns.includes(index) ? 'left' : (rightFixedColumns.includes(index) ? 'right' : '');
 
      const className: string = classNames('st-table-cell', column.className, fixed ? ('st-table-cell-fix-' + fixed) : '');
 
      const rawValue: any = (column.dataKey && column.dataKey in record) ? record[column.dataKey] : undefined;
 
      let value: any = undefined;
 
      if (column.render) {
 
        value = column.render(rawValue, record, index);
 
      } else {
 
        value = (rawValue === undefined || rawValue === null) ? '' : String(rawValue);
 
      }
 
      return (
 
        <td
 
          key={index}
 
          className={className}
 
          style={{textAlign: align}}
 
        >
 
          {value}
 
        </td>
 
      );
 
    });
 
  }
 
  export default ScrollableTable;
 
  components/ScrollableTable/index.less
 
  .st-table-container {
 
    border: 1px solid #f0f0f0;
 
    border-right: 0;
 
    border-bottom: 0;
 
    font-size: 14px;
 
    .st-table-header {
 
      border-right: 1px solid #f0f0f0;
 
      overflow: hidden;
 
      table {
 
        border-collapse: separate;
 
        border-spacing: 0;
 
        table-layout: fixed;
 
        width: 100%;
 
        thead.st-table-thead {
 
          tr {
 
            th.st-table-cell {
 
              background: #fafafa;
 
              border-bottom: 1px solid #f0f0f0;
 
              border-right: 1px solid #f0f0f0;
 
              color: rgba(0, 0, 0, .85);
 
              font-weight: 500;
 
              padding: 8px;
 
              text-align: left;
 
              &:last-child {
 
                border-right: 0;
 
              }
 
            }
 
          }
 
        }
 
      }
 
    }
 
    .st-table-body {
 
      overflow: auto scroll;
 
      border-bottom: 1px solid #f0f0f0;
 
      border-right: 1px solid #f0f0f0;
 
      table {
 
        border-collapse: separate;
 
        border-spacing: 0;
 
        table-layout: fixed;
 
        tbody.st-table-tbody {
 
          tr.st-table-row {
 
            td.st-table-cell  {
 
              border-bottom: 1px solid #f0f0f0;
 
              border-right: 1px solid #f0f0f0;
 
              color: rgba(0, 0, 0, .65);
 
              padding: 8px;
 
              text-align: left;
 
              &:last-child {
 
                border-right: 0;
 
              }
 
            }
 
            &:last-child {
 
              td.st-table-cell  {
 
                border-bottom: 0;
 
              }
 
            }
 
          }
 
        }
 
      }
 
    }
 
    table {
 
      .st-table-cell {
 
        &.st-table-cell-fix-left {
 
          background: #fff;
 
          position: sticky;
 
          left: 0;
 
          z-index: 2;
 
        }
 
        &.st-table-cell-fix-right {
 
          background: #fff;
 
          position: sticky;
 
          right: 0;
 
          z-index: 2;
 
        }
 
      }
 
    }
 
  }
 
  然后可以这样使用:
 
  views/Test/index.tsx
 
  import React, { FunctionComponent } from 'react';
 
  import Page from '../../components/Page';
 
  import ScrollableTable from '../../components/ScrollableTable';
 
  import StoreProvider from '../../stores/products/context';
 
  import './index.less';
 
  const Test: FunctionComponent<any> = (props: any) => {
 
    let records: any[] = [{
 
      id: 1,
 
      productName: '淡泰',
 
      amount1: 198,
 
      amount2: 200,
 
      amount3: 205.5,
 
      currency: '人民币',
 
      ca: 'Amy'
 
    }, {
 
      productName: '方润',
 
      amount1: 105.5,
 
      amount2: 100,
 
      amount3: 108,
 
      currency: '港元',
 
      ca: 'Baby'
 
    }, {
 
      productName: '医疗基金-1',
 
      amount1: 153,
 
      amount2: 150,
 
      amount3: 155,
 
      currency: '人民币',
 
      ca: 'Emily'
 
    }, {
 
      productName: '医疗基金-2',
 
      amount1: 302,
 
      amount2: 300,
 
      amount3: 290,
 
      currency: '美元',
 
      ca: 'Baby'
 
    }, {
 
      productName: '医疗基金-3',
 
      amount1: 108.8,
 
      amount2: 100,
 
      amount3: 130,
 
      currency: '人民币',
 
      ca: 'Amy'
 
    }, {
 
      productName: '医疗基金-4',
 
      amount1: 205,
 
      amount2: 200,
 
      amount3: 208,
 
      currency: '美元',
 
      ca: '吴丹'
 
    }, {
 
      productName: '医疗基金-5',
 
      amount1: 315.5,
 
      amount2: 300,
 
      amount3: 280,
 
      currency: '人民币',
 
      ca: 'Baby'
 
    }, {
 
      productName: '医疗基金-6',
 
      amount1: 109,
 
      amount2: 95,
 
      amount3: 106,
 
      currency: '人民币',
 
      ca: 'Emily'
 
    }, {
 
      productName: '恒大私募债',
 
      amount1: 213,
 
      amount2: 200,
 
      amount3: 208,
 
      currency: '港元',
 
      ca: '吴丹'
 
    }];
 
    const totalRecord: any = {
 
      productName: '合计',
 
      amount1: {},
 
      amount2: {},
 
      amount3: {}
 
    };
 
    records.forEach((record: any) => {
 
      const currency: string = record.currency;
 
      ['amount1', 'amount2', 'amount3'].forEach((key: string) => {
 
        const value: any = totalRecord[key];
 
        if (!(currency in value)) value[currency] = 0;
 
        value[currency] += record[key];
 
      });
 
    });
 
    records.push(totalRecord);
 
    const columns: any[] = [{
 
      dataKey: 'productName',
 
      title: '产品名称',
 
      width: 90,
 
      fixed: true
 
    }, {
 
      dataKey: 'amount1',
 
      title: <React.Fragment>上周缴款金额<br/>(万)</React.Fragment>,
 
      width: 140,
 
      align: 'center',
 
      className: 'amount',
 
      render: calculateTotal
 
    }, {
 
      dataKey: 'amount2',
 
      title: <React.Fragment>上周预约金额<br/>(万)</React.Fragment>,
 
      width: 140,
 
      align: 'center',
 
      className: 'amount',
 
      render: calculateTotal
 
    }, {
 
      dataKey: 'amount3',
 
      title: <React.Fragment>待本周跟进金额<br/>(万)</React.Fragment>,
 
      width: 140,
 
      align: 'center',
 
      className: 'amount',
 
      render: calculateTotal
 
    }, {
 
      dataKey: 'currency',
 
      title: '币种',
 
      width: 80
 
    }, {
 
      dataKey: 'ca',
 
      title: 'CA',
 
      width: 80
 
    }];
 
    return (
 
      <StoreProvider>
 
        <Page
 
          {...props}
 
          title="销售统计"
 
          className="test"
 
        >
 
          <div style={{padding: 15}}>
 
            <ScrollableTable
 
              width={window.innerWidth - 30}
 
              height={196}
 
              columns={columns}
 
              dataSource={records}
 
            />
 
          </div>
 
        </Page>
 
      </StoreProvider>
 
    );
 
  };
 
  function calculateTotal(value: any) {
 
    if (value instanceof Object) {
 
      const keys: any[] = Object.keys(value);
 
      return (
 
        <React.Fragment>
 
          {
 
            keys.map((key: string, index: number) => (
 
              <span key={index}>
 
                {`${value[key].toFixed(2)}万${key}`}
 
              </span>
 
            ))
 
          }
 
        </React.Fragment>
 
      )
 
    }
 
    return value.toFixed(2);
 
  }
 
  export default Test;
 
  views/Test/index.less
 
  .st-table-container {
 
    .st-table-body {
 
      td.st-table-cell.amount {
 
        padding-right: 20px !important;
 
        text-align: right !important;
 
        span {
 
          display: block;
 
        }
 
      }
 
   &
 

(编辑:厦门网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章