У меня есть простая пользовательская карусель React:
https://codesandbox.io/s/infallible-wood-740s2?fontsize=14
Он проходит через числа от 1 до 100. Я пытаюсь, чтобы активное число было центрировано с большим размером шрифта, а его соседи с меньшим размером шрифта:
Чтобы пройти через эту карусель, вы должны нажать на карусель.
Проблема в том, что прогресс по номерам карусели начинает смещаться. Я полагаю, что это из-за неправильного расчета для свойства 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)}
`;