So erreichen Sie die Tabellenkopffixierung in React

藏色散人
Freigeben: 2023-01-09 10:25:11
Original
972 Leute haben es durchsucht

So implementieren Sie einen festen Tabellenkopf in React: 1. Implementieren Sie einen festen Tabellenkopf über die Tabellenkomponente von Ant Design. 2. Verwenden Sie „rc-table“, um einen festen Tabellenkopf auf dem mobilen Endgerät zu implementieren onscroll-Ereignis von div scrollLeft-Eigenschaft von div.

So erreichen Sie die Tabellenkopffixierung in React

Die Betriebsumgebung dieses Tutorials: Windows 10-System, Reaktionsversion 18.0.0, Dell G3-Computer.

Wie behebe ich den Header in React?

React-Tabelle mit festem Kopf und gesperrten Spalten

Die Tabellenkomponente von Ant Design ist sehr einfach zu verwenden. Sie verfügt über die Funktionen von festem Kopf und gesperrten Spalten, Ant Design Mobile verfügt jedoch nicht über die Tabellenkomponente. Um die Funktionen von festen Tabellenköpfen und gesperrten Spalten auf dem mobilen Endgerät zu implementieren, sollten Sie rc-table verwenden können, oder Sie können natürlich auch selbst eines schreiben.

Durch die Analyse der Tabelle von AntD können wir sehen, dass die Tabelle mit einem festen Header aus zwei

-Tags besteht, die jeweils in divs verschachtelt sind. Der obere ist der Tabellenheader, der nur enthält ;. Nachfolgend finden Sie den Tabelleninhalt, der nur enthält. Sie sollten das Onscroll-Ereignis des Div unten abhören und das scrollLeft-Attribut des Div oben ändern, sodass beim horizontalen Scrollen der Tabelle auch der Tabellenkopf synchron gescrollt wird. Feste Spalten werden erreicht, indem die CSS-Eigenschaften position von th und td auf sticky und left oder right auf 0 gesetzt werden. Gleichzeitig wird z-index so eingestellt, dass die gesperrte Spalte immer oben angezeigt wird.

Sobald Sie das Prinzip verstanden haben, wird es einfacher, Code zu schreiben.

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 + &#39;px&#39;) : &#39;unset&#39;;
  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: &#39;key&#39;
    });
  }
  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(&#39;st-table-header&#39;);
    if (tableHeaders.length > 0) {
      tableHeaders[0].scrollLeft = scrollLeft;
    }
  };
  return (
    <div
      className={classNames(&#39;st-table-container&#39;, 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 || &#39;&#39;;
                  const fixed: string = leftFixedColumns.includes(index) ? &#39;left&#39; : (rightFixedColumns.includes(index) ? &#39;right&#39; : &#39;&#39;);
                  const fixedClassName: string = fixed ? (&#39;st-table-cell-fix-&#39; + fixed) : &#39;&#39;;
                  return (
                    <th
                      key={index}
                      className={classNames(&#39;st-table-cell&#39;, 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: &#39;100%&#39;}}>
          <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(&#39; &#39;);
}
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) ? &#39;left&#39; : (rightFixedColumns.includes(index) ? &#39;right&#39; : &#39;&#39;);
    const className: string = classNames(&#39;st-table-cell&#39;, column.className, fixed ? (&#39;st-table-cell-fix-&#39; + fixed) : &#39;&#39;);
    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) ? &#39;&#39; : 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;
      }
    }
  }
}
Nach dem Login kopieren

Dann kannst du es so verwenden:

views/Test/index.tsx
import React, { FunctionComponent } from &#39;react&#39;;
import Page from &#39;../../components/Page&#39;;
import ScrollableTable from &#39;../../components/ScrollableTable&#39;;
import StoreProvider from &#39;../../stores/products/context&#39;;
import &#39;./index.less&#39;;
const Test: FunctionComponent<any> = (props: any) => {
  let records: any[] = [{
    id: 1,
    productName: &#39;淡泰&#39;,
    amount1: 198,
    amount2: 200,
    amount3: 205.5,
    currency: &#39;人民币&#39;,
    ca: &#39;Amy&#39;
  }, {
    productName: &#39;方润&#39;,
    amount1: 105.5,
    amount2: 100,
    amount3: 108,
    currency: &#39;港元&#39;,
    ca: &#39;Baby&#39;
  }, {
    productName: &#39;医疗基金-1&#39;,
    amount1: 153,
    amount2: 150,
    amount3: 155,
    currency: &#39;人民币&#39;,
    ca: &#39;Emily&#39;
  }, {
    productName: &#39;医疗基金-2&#39;,
    amount1: 302,
    amount2: 300,
    amount3: 290,
    currency: &#39;美元&#39;,
    ca: &#39;Baby&#39;
  }, {
    productName: &#39;医疗基金-3&#39;,
    amount1: 108.8,
    amount2: 100,
    amount3: 130,
    currency: &#39;人民币&#39;,
    ca: &#39;Amy&#39;
  }, {
    productName: &#39;医疗基金-4&#39;,
    amount1: 205,
    amount2: 200,
    amount3: 208,
    currency: &#39;美元&#39;,
    ca: &#39;吴丹&#39;
  }, {
    productName: &#39;医疗基金-5&#39;,
    amount1: 315.5,
    amount2: 300,
    amount3: 280,
    currency: &#39;人民币&#39;,
    ca: &#39;Baby&#39;
  }, {
    productName: &#39;医疗基金-6&#39;,
    amount1: 109,
    amount2: 95,
    amount3: 106,
    currency: &#39;人民币&#39;,
    ca: &#39;Emily&#39;
  }, {
    productName: &#39;恒大私募债&#39;,
    amount1: 213,
    amount2: 200,
    amount3: 208,
    currency: &#39;港元&#39;,
    ca: &#39;吴丹&#39;
  }];
  const totalRecord: any = {
    productName: &#39;合计&#39;,
    amount1: {},
    amount2: {},
    amount3: {}
  };
  records.forEach((record: any) => {
    const currency: string = record.currency;
    [&#39;amount1&#39;, &#39;amount2&#39;, &#39;amount3&#39;].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: &#39;productName&#39;,
    title: &#39;产品名称&#39;,
    width: 90,
    fixed: true
  }, {
    dataKey: &#39;amount1&#39;,
    title: <React.Fragment>上周缴款金额<br/>(万)</React.Fragment>,
    width: 140,
    align: &#39;center&#39;,
    className: &#39;amount&#39;,
    render: calculateTotal
  }, {
    dataKey: &#39;amount2&#39;,
    title: <React.Fragment>上周预约金额<br/>(万)</React.Fragment>,
    width: 140,
    align: &#39;center&#39;,
    className: &#39;amount&#39;,
    render: calculateTotal
  }, {
    dataKey: &#39;amount3&#39;,
    title: <React.Fragment>待本周跟进金额<br/>(万)</React.Fragment>,
    width: 140,
    align: &#39;center&#39;,
    className: &#39;amount&#39;,
    render: calculateTotal
  }, {
    dataKey: &#39;currency&#39;,
    title: &#39;币种&#39;,
    width: 80
  }, {
    dataKey: &#39;ca&#39;,
    title: &#39;CA&#39;,
    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;
      }
    }
  }
}
Nach dem Login kopieren

Empfohlenes Lernen: „Video-Tutorial reagieren

Das obige ist der detaillierte Inhalt vonSo erreichen Sie die Tabellenkopffixierung in React. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage