内表中的最后一行不会在固定数据表中展开

Posted

技术标签:

【中文标题】内表中的最后一行不会在固定数据表中展开【英文标题】:Last rows in inner table don't expand in Fixed Data Table 【发布时间】:2018-11-13 22:16:11 【问题描述】:

我在 fixed-data-table-2 组件中使用expanded rows。我在内表上有 3 个级别:

如果我单击内表(第二个嵌套级别)中的折叠单元格,行不会展开并且最后一个嵌套表不会呈现。它发生在第一次单击父行后,但在第二次单击后呈现表格。

更奇怪的是,如果 a)我单击第二个表的前三行或 b)如果我在主(第一)表中展开第一行

如果不是主表的第一行被展开,第二个表的最后一行就会发生这种情况。

您可以在 this 和 this 录制中看到此行为。

codesandbox

CollapseCell.jsx

import React from 'react';
import  Cell  from 'fixed-data-table-2';

const  StyleSheet, css  = require('aphrodite');

export default class CollapseCell extends React.PureComponent 
  render() 
    const 
      data, rowIndex, columnKey, collapsedRows, callback, ...props
     = this.props;
    return (
      <Cell ...props className=css(styles.collapseCell)>
        <a onClick=evt => callback(rowIndex)>collapsedRows.has(rowIndex) ? '\u25BC' : '\u25BA'</a>
      </Cell>
    );
  


const styles = StyleSheet.create(
  collapseCell: 
    cursor: 'pointer',
  ,
);

TestMeet.jsx

import React,  Component  from 'react';
import debounce from 'lodash/debounce';
import  Table, Column, Cell  from 'fixed-data-table-2';
import isEmpty from 'lodash/isEmpty';
import 'fixed-data-table-2/dist/fixed-data-table.min.css';
import CollapseCell from './CollapseCell.jsx';
import SecondInnerTable from './SecondInnerTable';

const  StyleSheet, css  = require('aphrodite');

export default class TestMeetView extends Component 
  static propTypes = ;

  state = 
    tableData: [
      
        start: '5/19',
        end: '5/20',
        host: 'DACA',
      ,
      
        start: '6/15',
        end: '6/15',
        host: 'DACA',
      ,
      
        start: '6/16',
        end: '6/17',
        host: 'DACA',
      ,
      
        start: '7/15',
        end: '7/16',
        host: 'DACA',
      ,
      
        start: '7/30',
        end: '7/31',
        host: 'DACA',
      ,
    ],
    columnWidths: 
      start: 200,
      end: 200,
      host: 200,
      action: 100,
    ,
    tableContainerWidth: 0,
    numOfExpRows: 0,
    expChildRows: ,
    collapsedRows: new Set(),
    scrollToRow: null,
  ;

  componentDidMount() 
    this.updateWidth();
    this.updateWidth = debounce(this.updateWidth, 200);
    window.addEventListener('resize', this.updateWidth);
  

  componentWillUnmount() 
    window.removeEventListener('resize', this.updateWidth);
  

  onTableColumnResizeEndCallback = (newColumnWidth, columnKey) => 
    this.setState(( columnWidths ) => (
      columnWidths: 
        ...columnWidths,
        [columnKey]: newColumnWidth,
      ,
    ));
  ;

  updateWidth = () => 
    if (this.tableContainer.offsetWidth === this.state.tableContainerWidth) 
      return;
    

    if (
      this.tableContainer &&
      this.tableContainer.offsetWidth !== this.state.tableContainerWidth
    ) 
      const newTableContainerWidth = this.tableContainer.offsetWidth;
      this.setState(
        tableContainerWidth: newTableContainerWidth,
        columnWidths: 
          start: newTableContainerWidth / 3,
          end: newTableContainerWidth / 3,
          host: newTableContainerWidth / 3,
        ,
      );
    
  ;

  handleCollapseClick = (rowIndex) => 
    const  collapsedRows  = this.state;
    const shallowCopyOfCollapsedRows = new Set([...collapsedRows]);
    let scrollToRow = rowIndex;
    if (shallowCopyOfCollapsedRows.has(rowIndex)) 
      shallowCopyOfCollapsedRows.delete(rowIndex);
      scrollToRow = null;
     else 
      shallowCopyOfCollapsedRows.add(rowIndex);
    

    let numOfExpRows = 0;
    if (collapsedRows.size > 0) 
      numOfExpRows = collapsedRows.size;
    

    let resetExpChildRow = -1;
    if (collapsedRows.has(rowIndex)) 
      numOfExpRows -= 1;
      resetExpChildRow = rowIndex;
     else 
      numOfExpRows += 1;
    

    if (resetExpChildRow === -1) 
      this.setState(
        numOfExpRows,
        scrollToRow,
        collapsedRows: shallowCopyOfCollapsedRows,
      );
     else 
      this.setState(
        numOfExpRows,
        scrollToRow,
        collapsedRows: shallowCopyOfCollapsedRows,
        expChildRows: 
          ...this.state.expChildRows,
          [rowIndex]: 0,
        ,
      );
    
  ;

  subRowHeightGetter = (index) => 
    const numExpChildRows = this.state.expChildRows[index] ? this.state.expChildRows[index] : 0;
    return this.state.collapsedRows.has(index) ? 242 * (numExpChildRows + 1) + 50 : 0;
  ;

  rowExpandedGetter = ( rowIndex, width, height ) => 
    if (!this.state.collapsedRows.has(rowIndex)) 
      return null;
    

    const style = 
      height,
      width: width - 10,
    ;

    return (
      <div style=style>
        <div className=css(styles.expandStyles)>
          <SecondInnerTable
            changeNumOfExpandedRows=this.setNumOfInnerExpandedRows
            parentRowIndex=rowIndex
          />
        </div>
      </div>
    );
  ;

  setNumOfInnerExpandedRows = (numOfExpandedRows, rowIndex) => 
    this.setState(
      expChildRows: 
        ...this.state.expChildRows,
        [rowIndex]: numOfExpandedRows,
      ,
    );
  ;

  render() 
    let sumOfExpChildRows = 0;
    if (!isEmpty(this.state.expChildRows)) 
      sumOfExpChildRows = Object.values(this.state.expChildRows).reduce((a, b) => a + b);
    
    return (
      <div className="test-view">
        <div className="container-fluid">
          <div className="mb-5" ref=el => (this.tableContainer = el)>
            <Table
              scrollToRow=this.state.scrollToRow
              rowsCount=this.state.tableData.length
              rowHeight=40
              headerHeight=40
              width=this.state.tableContainerWidth
              height=(this.state.numOfExpRows + sumOfExpChildRows + 1) * 242
              subRowHeightGetter=this.subRowHeightGetter
              rowExpanded=this.rowExpandedGetter
              touchScrollEnabled
              onColumnResizeEndCallback=this.onTableColumnResizeEndCallback
              isColumnResizing=false
            >
              <Column
                cell=<CollapseCell callback=this.handleCollapseClick collapsedRows=this.state.collapsedRows />
                fixed
                width=30
              />
              <Column
                columnKey="start"
                header=<Cell>Start</Cell>
                cell=props => <Cell ...props>this.state.tableData[props.rowIndex].start</Cell>
                width=this.state.columnWidths.start
                isResizable
              />
              <Column
                columnKey="end"
                header=<Cell>End</Cell>
                cell=props => <Cell ...props>this.state.tableData[props.rowIndex].end</Cell>
                width=this.state.columnWidths.end
                isResizable
              />
              <Column
                columnKey="host"
                header=<Cell>Host</Cell>
                cell=props => <Cell ...props>this.state.tableData[props.rowIndex].host</Cell>
                width=this.state.columnWidths.host
                isResizable
              />
            </Table>
          </div>
        </div>
      </div>
    );
  


const styles = StyleSheet.create(
  expandStyles: 
    height: '242px',
    margin: '10px',
  ,
);

SecondInnerTable.jsx

import React,  Component  from 'react';
import  Table, Column, Cell  from 'fixed-data-table-2';
import debounce from 'lodash/debounce';
import 'fixed-data-table-2/dist/fixed-data-table.min.css';
import CollapseCell from './CollapseCell';
import ThirdInnerTable from './ThirdInnerTable';

const  StyleSheet, css  = require('aphrodite');

export default class SecondInnerTable extends Component 
  state = 
    tableData: [
      
        dateOfSession: '5/19/18',
        timeline: '4h00m/4h30m',
        entries: '400/900',
      ,
      
        dateOfSession: '5/19/18',
        timeline: '4h00m/4h30m',
        entries: '400/900',
      ,
      
        dateOfSession: '5/19/18',
        timeline: '4h00m/4h30m',
        entries: '400/900',
      ,
      
        dateOfSession: '5/19/18',
        timeline: '4h00m/4h30m',
        entries: '400/900',
      ,
      
        dateOfSession: '5/19/18',
        timeline: '4h00m/4h30m',
        entries: '400/900',
      ,
    ],
    tableColumns: 
      dateOfSession:  label: 'Date of Session', width: 150 ,
      timeline:  label: 'Timeline', width: 150 ,
      entries:  label: 'Entries', width: 150 ,
    ,
    tableContainerWidth: 0,
    tableContainerHeight: 252,
    collapsedRows: new Set(),
    scrollToRow: null,
  ;

  componentDidMount() 
    this.updateWidth();
    this.updateWidth = debounce(this.updateWidth, 200);
    window.addEventListener('resize', this.updateWidth);
  

  componentWillUnmount() 
    window.removeEventListener('resize', this.updateWidth);
  

  onSessionsTableColumnResizeEndCallback = (newColumnWidth, columnKey) => 
    this.setState(( tableColumns ) => (
      tableColumns: 
        ...tableColumns,
        [columnKey]:  label: tableColumns[columnKey].label, width: newColumnWidth ,
      ,
    ));
  ;

  updateWidth = () => 
    if (this.tableContainer.offsetWidth === this.state.tableContainerWidth) 
      return;
    
    if (
      this.tableContainer &&
      this.tableContainer.offsetWidth !== this.state.tableContainerWidth
    ) 
      const newTableContainerWidth = this.tableContainer.offsetWidth - 20;
      const newColumnsWidth = newTableContainerWidth / 3;
      this.setState(( tableColumns ) => (
        tableContainerWidth: newTableContainerWidth,
        tableColumns: 
          dateOfSession:  label: tableColumns.dateOfSession.label, width: newColumnsWidth ,
          timeline:  label: tableColumns.timeline.label, width: newColumnsWidth ,
          entries:  label: tableColumns.entries.label, width: newColumnsWidth ,
        ,
      ));
    
  ;

  handleCollapseClick = (rowIndex) => 
    const  collapsedRows  = this.state;
    const shallowCopyOfCollapsedRows = new Set([...collapsedRows]);
    let scrollToRow = rowIndex;
    if (shallowCopyOfCollapsedRows.has(rowIndex)) 
      shallowCopyOfCollapsedRows.delete(rowIndex);
      scrollToRow = null;
     else 
      shallowCopyOfCollapsedRows.add(rowIndex);
    

    let numOfExpRows = 0;
    if (collapsedRows.size > 0) 
      numOfExpRows = collapsedRows.size;
    

    if (collapsedRows.has(rowIndex)) 
      numOfExpRows -= 1;
     else 
      numOfExpRows += 1;
    

    this.setState(
      
        tableContainerHeight: 252 * (numOfExpRows + 1),
        scrollToRow,
        collapsedRows: shallowCopyOfCollapsedRows,
      ,
      () => 
        this.props.changeNumOfExpandedRows(numOfExpRows, this.props.parentRowIndex);
      ,
    );
  ;

  subRowHeightGetter = index => (this.state.collapsedRows.has(index) ? 272 : 0);

  rowExpandedGetter = ( rowIndex, width, height ) => 
    if (!this.state.collapsedRows.has(rowIndex)) 
      return null;
    

    const style = 
      height,
      width: width - 10,
    ;
    return (
      <div style=style>
        <div className=css(styles.expandStyles)>
          <ThirdInnerTable parentRowIndex=rowIndex />
        </div>
      </div>
    );
  ;

  render() 
    return (
      <div className="mb-2" ref=el => (this.tableContainer = el)>
        <Table
          scrollToRow=this.state.scrollToRow
          rowsCount=this.state.tableData.length
          rowHeight=40
          headerHeight=50
          width=this.state.tableContainerWidth
          height=this.state.tableContainerHeight
          subRowHeightGetter=this.subRowHeightGetter
          rowExpanded=this.rowExpandedGetter
          touchScrollEnabled
          onColumnResizeEndCallback=this.onSessionsTableColumnResizeEndCallback
          isColumnResizing=false
        >
          <Column
            cell=<CollapseCell callback=this.handleCollapseClick collapsedRows=this.state.collapsedRows />
            fixed
            width=30
          />
          Object.keys(this.state.tableColumns).map(key => (
            <Column
              key=key
              columnKey=key
              header=<Cell>this.state.tableColumns[key].label</Cell>
              cell=props => <Cell ...props>this.state.tableData[props.rowIndex][key]</Cell>
              width=this.state.tableColumns[key].width
              isResizable
            />
          ))
        </Table>
      </div>
    );
  


const styles = StyleSheet.create(
  expandStyles: 
    height: '252px',
    margin: '10px',
  ,
);

ThirdInnerTable.jsx

import React,  Component  from 'react';
import debounce from 'lodash/debounce';
import  Table, Column, Cell  from 'fixed-data-table-2';
import 'fixed-data-table-2/dist/fixed-data-table.min.css';

export default class ThirdInnerTable extends Component 
  state = 
    tableData: [
      
        eventNumber: '1',
        qualifyingTime: 'N/A',
        selected: 'N/A',
      ,
      
        eventNumber: '1',
        qualifyingTime: 'N/A',
        selected: 'N/A',
      ,
      
        eventNumber: '1',
        qualifyingTime: 'N/A',
        selected: 'N/A',
      ,
      
        eventNumber: '1',
        qualifyingTime: 'N/A',
        selected: 'N/A',
      ,
      
        eventNumber: '1',
        qualifyingTime: 'N/A',
        selected: 'N/A',
      ,
    ],
    tableColumns: 
      eventNumber:  label: 'Event number', width: 150 ,
      qualifyingTime:  label: 'Qualifying time', width: 150 ,
      selected:  label: 'Selected?', width: 150 ,
    ,
    tableContainerWidth: 0,
    numOfColumns: 3,
  ;

  componentDidMount() 
    this.updateWidth();
    this.updateWidth = debounce(this.updateWidth, 200);
    window.addEventListener('resize', this.updateWidth);
  

  componentWillUnmount() 
    window.removeEventListener('resize', this.updateWidth);
  

  onEventsTableColumnResizeEndCallback = (newColumnWidth, columnKey) => 
    this.setState(( tableColumns ) => (
      tableColumns: 
        ...tableColumns,
        [columnKey]:  label: tableColumns[columnKey].label, width: newColumnWidth ,
      ,
    ));
  ;

  updateWidth = () => 
    if (this.tableContainer.offsetWidth === this.state.tableContainerWidth) 
      return;
    
    if (
      this.tableContainer &&
      this.tableContainer.offsetWidth !== this.state.tableContainerWidth
    ) 
      const newTableContainerWidth = this.tableContainer.offsetWidth;
      const columnWidth = newTableContainerWidth / 3;

      this.setState(( tableColumns ) => (
        tableContainerWidth: newTableContainerWidth,
        tableColumns: 
          eventNumber:  label: tableColumns.eventNumber.label, width: columnWidth ,
          qualifyingTime:  label: tableColumns.qualifyingTime.label, width: columnWidth ,
          selected:  label: tableColumns.selected.label, width: columnWidth ,
        ,
      ));
    
  ;

  render() 
    return (
      <div className="mb-5" ref=el => (this.tableContainer = el)>
        <Table
          rowsCount=this.state.tableData.length
          rowHeight=40
          headerHeight=50
          width=this.state.tableContainerWidth
          height=252
          touchScrollEnabled
          onColumnResizeEndCallback=this.onEventsTableColumnResizeEndCallback
          isColumnResizing=false
        >
          Object.keys(this.state.tableColumns).slice(0, this.state.numOfColumns).map(key => (
            <Column
              key=key
              columnKey=key
              header=<Cell>this.state.tableColumns[key].label</Cell>
              cell=props => <Cell ...props>this.state.tableData[props.rowIndex][key]</Cell>
              width=this.state.tableColumns[key].width
              isResizable
            />
            ))
        </Table>
      </div>
    );
  

【问题讨论】:

一切正常 @udayakumar 检查this 和this 录音 是的,我看到了你的问题。第一次点击对我有用。您只需要准确地对准黑色箭头即可。关于渲染问题,我认为这与滚动的内部组件有关。整体滚动对我来说相当滞后 【参考方案1】:

我已经更新了沙盒代码,请查看下面的链接,我认为它对你有用

Code Sandbox

或者

    handleCollapseClick = rowIndex => 
    const  collapsedRows  = this.state;

    const shallowCopyOfCollapsedRows = new Set([...collapsedRows]);
    let scrollToRow = rowIndex;
    if (shallowCopyOfCollapsedRows.has(rowIndex)) 
      shallowCopyOfCollapsedRows.delete(rowIndex);
      scrollToRow = null;
     else 
      shallowCopyOfCollapsedRows.add(rowIndex);
    

    let numOfExpRows = 0;
    if (collapsedRows.size > 0) 
      numOfExpRows = collapsedRows.size;
    

    let resetExpChildRow = -1;
    if (collapsedRows.has(rowIndex)) 
      numOfExpRows -= 1;
      resetExpChildRow = rowIndex;
     else 
      numOfExpRows += 1;
    

    if (resetExpChildRow === -1) 
      this.setState(
        tableContainerHeight: 250 * numOfExpRows,
        scrollToRow,
        collapsedRows: shallowCopyOfCollapsedRows
      );
     else 
      this.setState(
        numOfExpRows,
        scrollToRow,
        collapsedRows: shallowCopyOfCollapsedRows,
        expChildRows: 
          ...this.state.expChildRows,
          [rowIndex]: 0
        
      );
    
  ;

【讨论】:

谢谢,但是当我尝试您的示例时,我遇到了同样的问题。我用你的沙盒创建了一个recording,你可以在其中看到问题。 好的,我会检查的@Matt 谢谢,我检查了你的codesandox,但是内表(第二层)的高度有些奇怪。我创建了一个新的recording,您可以在其中看到它。行展开后,内表的水平滚动条不可见。如果您在内表中展开/关闭行,则内表的高度不正确。无论如何,我认为我们已经接近解决方案。我正在处理某事,无法检查您的代码,但我会尽快检查。 你现在可以检查一下吗? @马特 现在看起来好多了。感谢您的帮助,您的回答应该被奖励。【参考方案2】:

我应该发表评论,但我没有所需的编号。的点。你解决了这个问题吗?因为我刚刚打开了你附加的链接,它工作正常

更新 您的代码工作正常。您的方法的问题是您的点击事件是在箭头上触发的,而不是在整个 div (或单元格)上触发的。因此,您需要准确无误,只需单击箭头即可展开您的行。如果您不想要这种行为,我建议您将点击事件放在 div(或单元格)上

这是一个工作视频,证明它工作正常: https://www.useloom.com/share/2c725f3fede942b09c661a765c72634e

我从您的视频中截取了屏幕截图,显示由于您没有点击箭头,这就是您的行没有展开的原因

【讨论】:

您使用的是哪种浏览器? 我用的是chrome浏览器 我不相信你没有这个问题...你认为你可以创建一个简短的.gif录音并将其上传到imgur,比如this吗? 好吧,让我想想。我可能误解了你的问题 你可以在this和this录音中看到这个问题

以上是关于内表中的最后一行不会在固定数据表中展开的主要内容,如果未能解决你的问题,请参考以下文章

ABAP中,用Ranges定义的内表,由于数据量大导致运行错误

abap语法中结构体与内表有啥区别?

ABAP从较大内表取部分数据到较小内表中 怎么取 可以按字段直接取数吗?

详解ABAP/4内表结构

如何在引导响应表中为一行保持固定大小?

abap怎么把字段类型不一样的一个内表的数据填充到另外一个内表中。