【发布时间】:2022-12-21 20:41:29
【问题描述】:
我正在尝试制作一个包含三列的 div,其中所有三列都通过动画滚动到底部。
当到达底部时,他们应该开始滚动到顶部。然后当到达顶部时,他们应该再次开始滚动到底部,依此类推。
我正在使用 React,我尝试通过将每列的顶部位置添加到状态并在 setInterval 中更改它来做到这一点。然后我尝试检测是否到达顶部的底部,然后相应地更改顶部位置。
问题是它滚动到底部,但是由于某种原因它不会滚动到顶部。我不确定为什么下一个代码不起作用。
代码如下:
import React, { useState, useEffect } from "react";
import { map } from "lodash";
const column1InitialYPosition = -300;
const column2InitialYPosition = -150;
const column3InitialYPosition = 0;
const intervalTime = 500;
const imageUrl =
"https://images.freeimages.com/variants/jzAZ1zYpxh11gSbgYPMheWun/f4a36f6589a0e50e702740b15352bc00e4bfaf6f58bd4db850e167794d05993d";
const column1Images = [imageUrl, imageUrl, imageUrl, imageUrl, imageUrl];
const column2Images = [imageUrl, imageUrl, imageUrl, imageUrl, imageUrl];
const column3Images = [imageUrl, imageUrl, imageUrl, imageUrl, imageUrl];
const isElementInViewport = el => {
let r, html;
if (!el || 1 !== el.nodeType) {
return false;
}
html = document.documentElement;
r = el.getBoundingClientRect();
return !!r && r.bottom >= 0 && r.top <= html.clientHeight;
};
export default function App() {
const [column1YPosition, setColumn1YPosition] = useState(
column1InitialYPosition
);
const [column2YPosition, setColumn2YPosition] = useState(
column2InitialYPosition
);
const [column3YPosition, setColumn3YPosition] = useState(
column3InitialYPosition
);
let intervalScroll;
useEffect(() => {
setTimeout(() => startScrollInterval(), 3000);
return () => removeScrollToBottomInterval();
}, []);
const calculateNewPosition = (
currentPosition,
maxPosition,
minPosition,
bottomReached,
topReached
) => {
let newPosition = bottomReached
? currentPosition + 100
: currentPosition - 100;
newPosition = -1 * newPosition > maxPosition ? -maxPosition : newPosition;
newPosition = newPosition > minPosition ? minPosition - 1 : newPosition;
return newPosition;
};
const startScrollInterval = () => {
const screenHeight = window ? window?.innerHeight : 0;
const column1Bottom = document.getElementById("column-1-bottom");
const column1Top = document.getElementById("column-1-top");
const column1 = document.getElementById("column-1");
const column1MaxTop = column1 ? column1?.scrollHeight - screenHeight : 0;
const column2Bottom = document.getElementById("column-2-bottom");
const column2Top = document.getElementById("column-2-top");
const column2 = document.getElementById("column-2");
const column2MaxTop = column2 ? column2?.scrollHeight - screenHeight : 0;
const column3Bottom = document.getElementById("column-3-bottom");
const column3Top = document.getElementById("column-3-top");
const column3 = document.getElementById("column-3");
const column3MaxTop = column3 ? column3?.scrollHeight - screenHeight : 0;
const intervalHandler = () => {
const column1BottomReached = isElementInViewport(column1Bottom);
const column1TopReached = isElementInViewport(column1Top);
const column2BottomReached = isElementInViewport(column2Bottom);
const column2TopReached = isElementInViewport(column2Top);
const column3BottomReached = isElementInViewport(column3Bottom);
const column3TopReached = isElementInViewport(column3Top);
setColumn1YPosition(column1YPosition => {
return calculateNewPosition(
column1YPosition,
column1MaxTop,
column1InitialYPosition,
column1BottomReached,
column1TopReached
);
});
setColumn2YPosition(column2YPosition => {
return calculateNewPosition(
column2YPosition,
column2MaxTop,
column2InitialYPosition,
column2BottomReached,
column2TopReached
);
});
setColumn3YPosition(column3YPosition => {
return calculateNewPosition(
column3YPosition,
column3MaxTop,
column3InitialYPosition,
column3BottomReached,
column3TopReached
);
});
};
intervalScroll = setInterval(intervalHandler, intervalTime);
};
const removeScrollToBottomInterval = () => {
clearInterval(intervalScroll);
intervalScroll = null;
};
return (
<div className="relative w-full h-screen overflow-hidden">
<div className="grid grid-cols-3 px-24 gap-24">
<div className="relative overflow-hidden h-screen no-scrollbar">
<div
id="column-1"
className="absolute inset-0 grid grid-cols-1 gap-24"
style={{
transition: "all 6s linear",
top: column1YPosition
}}
>
{map(column1Images, (image, i) => {
const isFirst = i === 0;
const isLast = i === column1Images?.length - 1;
return (
<div key={`column-1-vehicle-${i}`} className="relative w-full">
<img src={image} alt="Vehicle" className="w-full h-80" />
{isFirst && (
<div
id="column-1-top"
className="absolute opacity-1 w-full h-20"
style={{ top: -1 * column1InitialYPosition }}
/>
)}
{isLast && (
<div
id="column-1-bottom"
className="absolute bottom-0 opacity-1 w-full h-20"
/>
)}
</div>
);
})}
</div>
</div>
<div className="relative overflow-hidden h-screen no-scrollbar">
<div
id="column-2"
className="absolute inset-0 grid grid-cols-1 gap-24"
style={{
transition: "all 5s linear",
top: column2YPosition
}}
>
{map(column2Images, (image, i) => {
const isFirst = i === 0;
const isLast = i === column2Images?.length - 1;
return (
<div key={`column-2-vehicle-${i}`} className="relative w-full">
<img src={image} alt="Vehicle" className="w-full h-80" />
{isFirst && (
<div
id="column-2-top"
className="absolute opacity-1 w-full h-20"
style={{ top: -1 * column2InitialYPosition }}
/>
)}
{isLast && (
<div
id="column-2-bottom"
className="absolute bottom-0 opacity-1 w-full h-20"
/>
)}
</div>
);
})}
</div>
</div>
<div className="relative overflow-hidden h-screen no-scrollbar">
<div
id="column-3"
className="absolute inset-0 grid grid-cols-1 gap-24"
style={{
transition: "all 6s linear",
top: column3YPosition
}}
>
{map(column3Images, (image, i) => {
const isFirst = i === 0;
const isLast = i === column3Images?.length - 1;
return (
<div key={`column-3-vehicle-${i}`} className="relative w-full">
<img src={image} alt="Vehicle" className="w-full h-80" />
{isFirst && (
<div
id="column-3-top"
className="absolute opacity-1 w-full h-20"
style={{ top: -1 * column3InitialYPosition }}
/>
)}
{isLast && (
<div
id="column-3-bottom"
className="absolute bottom-0 opacity-1 w-full h-20"
/>
)}
</div>
);
})}
</div>
</div>
</div>
</div>
);
}
我已经在沙箱中添加了一个示例。 Here is the link。
知道如何解决吗?
【问题讨论】:
-
你能创建一个最小的可重现示例吗?
-
codesandbox 的链接已经添加。
-
抱歉,我的意思是,是否可以缩短代码示例?
-
您的应用程序显示三个图像列并使用不同的初始 Y 偏移量,内部元素使用绝对位置,外部元素使用相对位置。垂直滚动到底部或顶部时可能会出现一些问题。你能不能只用一列来测试滚动的顶部和底部作为演示?
标签: javascript reactjs