Центрирование активного элемента внутри пользовательской карусели React - PullRequest
0 голосов
/ 05 июня 2019

У меня есть простая пользовательская карусель React:
https://codesandbox.io/s/infallible-wood-740s2?fontsize=14

Он проходит через числа от 1 до 100. Я пытаюсь, чтобы активное число было центрировано с большим размером шрифта, а его соседи с меньшим размером шрифта: enter image description here

Чтобы пройти через эту карусель, вы должны нажать на карусель.

Проблема в том, что прогресс по номерам карусели начинает смещаться. Я полагаю, что это из-за неправильного расчета для свойства left.

Я пытался настроить формулу, использовать React Transition Group и найти какой-то существующий пакет, который мог бы решить эту проблему, но мне это не удалось. Буду признателен за любую помощь.

Код компонента:

import React, { Component } from "react";
import ReactDOM from "react-dom";

import {
  Wrapper,
  NumbersWrapper,
  NumbersScroller,
  NumberText
} from "./Numbers.style";

const hundred = new Array(100)
  .fill(0)
  .map((k, v) => ({ key: v, label: v + 1 }));

class Numbers extends Component {
  constructor(props) {
    super(props);

    this.state = {
      activeNumber: 0
    };
  }

  setActiveNumber(number) {
    this.setState({
      activeNumber: number
    });
  }

  render() {
    const { activeNumber } = this.state;
    const intAciveNumber = Number(activeNumber);

    return (
      <Wrapper>
        <NumbersWrapper
          onClick={() => this.setActiveNumber(intAciveNumber + 1)}
        >
          <NumbersScroller
            style={{
              left: `${130 - intAciveNumber * 55}px`
            }}
          >
            {hundred.map(({ key, label }) => {
              const isNeighbor =
                key + 1 === activeNumber || key - 1 === activeNumber;
              const isActive = key === activeNumber;

              return (
                <NumberText
                  key={key}
                  isNeighbor={isNeighbor}
                  isActive={isActive}
                >
                  {label}
                </NumberText>
              );
            })}
          </NumbersScroller>
        </NumbersWrapper>
      </Wrapper>
    );
  }
}

export default Numbers;

const rootElement = document.getElementById("root");
ReactDOM.render(<Numbers />, rootElement);

Numbers.style.js:

import styled from "styled-components";

export const Wrapper = styled.div`
  height: 549px;
  width: 612px;
  border-radius: 28px;
  background-color: #ffffff;

  margin-top: 116px;
  padding: 26px 0 0 0;
  display: flex;
  flex-direction: column;
  align-items: center;

  position: absolute;
  left: 50%;
  top: 0%;
  transform: translate(-50%, -10%);
  overflow: hidden;
`;

export const NumbersWrapper = styled.div`
  white-space: nowrap;
  width: 359.5px;

  overflow: hidden;
`;

export const NumbersScroller = styled.div`
  transition: all 150ms ease-in;
  position: relative;
  left: 130px;
`;

const numberTextStyle = props => {
  if (props.isNeighbor) {
    return `
      height: 88px;
      width: 53px;
      opacity: 0.45;
      color: #6C879C;

      font-size: 80px;
      font-weight: 300;
      letter-spacing: -1.6px;
      line-height: 88px;
      text-align: center;
    `;
  }
  if (props.isActive) {
    return `
      height: 156px;
      color: #6C879C;

      font-size: 150px;
      font-weight: 300;
      letter-spacing: -3px;
      line-height: 156px;
      text-align: center;
    `;
  }

  return `
      opacity: 0.2;
      color: #6C879C;

      font-size: 40px;
      font-weight: 300;
      letter-spacing: -0.8px;
      line-height: 48px;
      text-align: center;
    `;
};

export const NumberText = styled.span`
  font-family: Avenir;
  margin: 0 15px;
  user-select: none;

  &:first-child {
    margin-left: 0;
  }

  &:last-child {
    margin-right: 0;
  }

  ${props => numberTextStyle(props)}
`;
...