Оптимизированная таблица (10 тыс строк)

Разработка Оптимизированная таблица (10 тыс строк)

Нет прав для скачивания
Оптимизированная таблица (10 тыс строк).
Пишем стиль:
SCSS:
$color-blue: #3a77ff;
$color-dark-blue: #28375a;
$row-height: 40px;
$table-gap: 1px;

html, body, .app {
  width: 100%;
  height: 100%;
  font-family: 'Montserrat', sans-serif;
}

.app {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba($color-blue, 0.2);
}

.table {
  background-color: rgba($color-blue, 0.2);
  border: 1px solid rgba($color-blue, 0.5);
  max-height: 80%;
  border-radius: 4px;
  box-shadow: 0 0 5px rgba($color-blue, 0.4), 0 0 25px rgba($color-blue, 0.2), 0 0 200px 150px white;
  display: flex;
  flex-direction: column;
  overflow: hidden;
 
  .header {
    display: grid;
    grid-template-columns: 70px repeat(5, 90px);
    grid-gap: $table-gap;
    border-bottom: 1px solid rgba($color-blue, 0.2);
    box-shadow: 0 0 2px 2px rgba($color-blue, 0.15), 0 0 15px 5px rgba($color-blue, 0.15);
    z-index: 1;
    font-weight: bold;
    
    .table-cell {
      background-color: mix($color-blue, white, 20%);
    }
  }
 
  .table-inner {
    display: grid;
    grid-template-columns: 70px repeat(5, 90px);
    grid-gap: $table-gap;
    height: 100%;
    overflow: auto;
  }
 
  .table-cell {
    padding: 0 15px;
    background-color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    height: $row-height;
    color: $color-dark-blue;
    
    &.column-0 {
      padding: 0 10px;
    }
    
    &.optimistic {
      position: relative;
      background-image: linear-gradient(rgba(58, 119, 255, 0.2) 1px, transparent 1px);
      background-size: $row-height+$table-gap $row-height+$table-gap;
      background-repeat: repeat;
      margin-top: -1px; // This fixes the double gab below the visible rows that occurs as a result of the gradient meeting the grid gap.
      
      &::after {
        content: '';
        position: absolute;
        width: 100%;
        height: 100%;
        top: 0;
        left: 0;
        // background-size: 80px 80px;
        animation: blink 2s infinite;
        background-repeat: repeat;
        background-image: linear-gradient(to right, transparent 0, transparent 10%, rgba(58, 119, 255, 0.1) 10%, rgba(58, 119, 255, 0.1) 90%, transparent 90%);
      }
    }
  }
}

@keyframes blink {
  0%, 100% {
    opacity: 0;
  }
  50% {
    opacity: 1;
  }
}
Пишем наш JS:
JavaScript:
const ROW_HEIGHT = 40;
const GAP_SIZE = 1;
const ROWS = 10000;
const COLS = 6;
const THRESHOLD = 300; // Represents the delay (in milliseconds) between data updates
const DATA_PADDING = 3; // Represents how much extra data should be rendered before
                        // and after the visibile rows to avoid showing empty rows
                        // when scrolling. This number is multiplied by the number
                        // of visible rows.

const OptimisticRow = ({rows}) => (
  <React.Fragment>
    {[...new Array(COLS)].map((_, i) => (
      <div key={i} className='table-cell optimistic' style={{height: rows *(ROW_HEIGHT + GAP_SIZE)}}/>
    ))}
  </React.Fragment>
);

const TableCell = ({children, index}) => (
  <div
    className={`table-cell column-${index}`}>
    {children}
  </div>
);

const TableRow = ({children}) => (
  children
);

class Table extends React.PureComponent {
 
  table = React.createRef();
  state = {from: 0, to: 30};
  previousScrolTop = 0;
 
  getSnapshotBeforeUpdate() {
    return this.table.current.scrollTop;
  }

  componentDidUpdate(prevProps, prevState, scrollTop) {
    // When the visible rows are moved down by changing
    // the height of the optimistic row above them, the browser automatically
    // scrolls them back into view, which in turn creates another render
    // becuase the onScroll is called, resulting in an infinite loop.
    // To solve this, we get the snapshot before the DOM is updated
    // and check for a mismatch between the scrollTop before and after.
    // If such a mismatch exists, it means that the scroll
    // was done by the browser, and not the user, and therefore
    // we apply the scrollTop from the snapshot.
    if (scrollTop !== this.table.current.scrollTop) {
      this.table.current.scrollTop = scrollTop;
    }
  }
 
  debounce = _.debounce((scrollTop, clientHeight) => {
    const maxVisibleRows = Math.ceil(clientHeight / (ROW_HEIGHT + GAP_SIZE));
    const from = Math.max(0, Math.floor(scrollTop / (ROW_HEIGHT + GAP_SIZE)) - maxVisibleRows * DATA_PADDING);
    const to = Math.min(this.props.rows, from + maxVisibleRows * (DATA_PADDING * 2 + 1));
    this.setState({from, to});
  }, THRESHOLD);
 
  handleOnScroll = e => {
    const {scrollTop, clientHeight} = e.target;
    this.debounce(scrollTop, clientHeight);
  };
 
  render() {
    const {children, rows} = this.props;
    const {from, to} = this.state;
    return (
      <div className='table'>
        <div className='header'>
          <TableRow>
            <TableCell index={0}>Index</TableCell>
            {[...new Array(COLS - 1)].map((_, i) => (
              <TableCell index={i + 1} header>Header</TableCell>
            ))}
          </TableRow>
        </div>
        <div className='table-inner' onScroll={this.handleOnScroll} ref={this.table}>
          {from > 0 &&
            <OptimisticRow rows={from}/>}
          {children(from, to)}
          {to < rows &&
            <OptimisticRow rows={rows - to}/>}
        </div>
      </div>
    );
  }
}

class App extends React.PureComponent {
 
  render() {
    return (
      <div className='app'>
        <Table rows={ROWS}>
          {(from, to) => (
            [...new Array(to - from)].map((_, i) => (
              <TableRow key={i} index={i}>
                <TableCell index={0}>{i + from}</TableCell>
                {[...new Array(COLS - 1)].map((_, i) => (
                  <TableCell index={i + 1} key={i}>data</TableCell>
                ))}
              </TableRow>
            ))
          )}
        </Table>
      </div>
    );
  }
}

ReactDOM.render(
  <App/>,
  document.body
);
Смотрим наш результат:
fg38.gif
Автор
baltun
Скачиваний
0
Просмотры
576
Первый выпуск
Обновление
Рейтинг
0.00 звёзд Оценок: 0

Ещё ресурсы от baltun

Назад
Верх Низ