Я пытаюсь создать календарь, который можно бесконечно прокручивать влево и вправо. Он должен динамически загружать новый контент, когда пользователь прокручивает вперед (легко) или назад (проблема здесь).
Когда я добавляю контент в конец страницы, он работает нормально - полоса прокрутки настраивается на новый container.scrollWidth
. Но когда мне нужно добавить контент в начало, весь календарь перемещается вправо огромным скачком в 400 пикселей, потому что свойство container.scrollLeft
не изменилось, и теперь в начале есть новый элемент.
Я пытаюсь смягчить это, увеличивая container.scrollLeft
на 400 пикселей - ширину вновь созданного элемента. Этот подход работает, но только при прокрутке с помощью колесика мыши (shift + колесо мыши для прокрутки в сторону) или мобильного сенсорного экрана.
Если я использую мышь для перетаскивания полосы прокрутки, это как бы сбоит - я предполагаю, что он продолжает попытки для прокрутки к старому положению scrollLeft
и не обращает внимания на то, что я увеличил его.
Не могли бы вы предложить способ достижения этого поведения для всех способов прокрутки?
Было бы также здорово, если бы вы можете просто указать мне на сайт, который использует эту технику, чтобы я мог исследовать себя.
Вот мой полуработающий пример:
function Container() {
const rectangleWidth = 400;
const container = React.useRef(null);
const [leftRectangles, setLeftRectangles] = React.useState([0]);
const [rightRectangles, setRightRectangles] = React.useState([1, 2, 3, 4]);
// When we just rendered a new rectangle in the left of our container,
// move the scroll position back
React.useEffect(() => {
container.current.scrollLeft += rectangleWidth;
}, [leftRectangles]);
const loadLeftRectangle = () => {
const newAddress = leftRectangles[0] - 1;
setLeftRectangles([newAddress, ...leftRectangles]);
};
const loadRightRectangle = () => {
const newAddress = rightRectangles[rightRectangles.length - 1] + 1;
setRightRectangles([...rightRectangles, newAddress]);
};
const handleScroll = (e) => {
// When there is only 100px of content left, load new content
const loadingOffset = 100;
if (e.target.scrollLeft < loadingOffset) {
loadLeftRectangle(e.target);
} else if (e.target.scrollLeft > e.target.scrollWidth - e.target.clientWidth - loadingOffset) {
loadRightRectangle(e.target);
}
};
return (
<div
className="container"
onScroll={handleScroll}
ref={container}
>
{leftRectangles.map((address) => (
<div className="rectangle" key={address}>
{address}
</div>
))}
{rightRectangles.map((address) => (
<div className="rectangle" key={address}>
{address}
</div>
))}
</div>
);
}
ReactDOM.render(<Container />, document.querySelector("#app"))
.container {
display: flex;
overflow-x: scroll;
}
.rectangle {
border: 1px solid #000;
box-sizing: border-box;
flex-shrink: 0;
height: 165px;
width: 400px;
font-size: 50px;
line-height: 165px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>
<div id="app"></div>