将固定内容移动到100vh组件的下方和上方
目前,我的屏幕中心有一个固定的图像,它在鼠标滚动时水平移动。我现在想在这个组件的上方和下方添加一个高度为100vh的屏幕。当我尝试这样做时,我的固定组件会自动移动到我想清空的屏幕顶部。我曾尝试向图像添加页边距顶部:100vh,但已将其移出屏幕。
这里有两件事我有问题。1是如何在100vh窗口之后将此组件放在屏幕中央,2是如何仅在用户到达该特定组件时启动动画。因为现在设置项目时,图像和文本会在用户滚动上移动,所以如果我在上面添加一个100vh的屏幕,则用户滚动已经开始,这将启动我的动画。
CodeSanbox(全屏查看更好的参考):https://codesandbox.io/s/interesting-bouman-lokt5?file=/src/App.js
编码:
{/* <div style={{height:"100vh"}}></div> */}
<div className="App" ref={ref}>
<h1 id="title" className="titles">
Random Title
</h1>
<section id="block1" className="blocks"></section>
<figure id="passport">
<img
alt="passport"
src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
/>
</figure>
<h2 id="text1" className="titles text1">
Random Text 1
</h2>
<section id="block2" className="blocks"></section>
<h2 id="text2" className="titles text2">
Random Text 2
</h2>
<section id="block3" className="blocks"></section>
<h2 id="text3" className="titles text3">
Random Text 3
</h2>
<section id="block4" className="blocks"></section>
</div>
{/* Stop Scrolling Animation */}
{/* <div>Content</div> */}
解决方案
此解决方案:
- 获取第一个元素的高度。
- 隐藏图像和第一个标题。
- 定义调用操作的时间。
- 显示或隐藏时添加其他检查。
沙盒示例link
function App() {
const [screen, setScreen] = React.useState(false);
const headerRef = React.useRef(null);
const mainRef = React.useRef(null);
// Reduce value if want the image to be closer to the edges
// otherwise to the center
const setImageLimitMovement = 1;
const setTextLimitMovement = 4;
const opacityRange = 400;
// Speed text movement
const speed = 1; // .5
React.useEffect(() => {
window.addEventListener('resize', () => {
if (window.innerWidth !== 0 || window.innerHeight !== 0) {
setScreen(window.innerWidth);
}
});
}, []);
React.useEffect(() => {
const app = [...mainRef.current.children];
const titles = app.filter(el => el.matches('.titles') && el);
const blocks = app.filter(el => el.matches('.blocks') && el);
const img = app.find(el => el.matches('#passport') && el);
const headerHeight = headerRef.current.getBoundingClientRect().height;
// Get the center point of blocks in an array
const centerPoints = blocks.map((blockEl, idx) => {
const blockindex = idx + 1;
const blockHeight = Math.floor(blockEl.getBoundingClientRect().height);
const blockHalf = blockHeight / 2;
return blockHeight * blockindex - blockHalf;
});
const leftMoveLimitImg = -centerPoints[0] / setImageLimitMovement;
const rightMoveLimitImg = centerPoints[0] / setImageLimitMovement;
const textLimit = centerPoints[0] / setTextLimitMovement;
// Hide when component mounted
titles[0].style.transform = `scale(0)`;
img.style.transform = `scale(0)`;
const changeBackground = () => {
const value = window.scrollY;
// Init
const startAction = headerHeight * 0.8;
// const startToHideInFooter = centerPoints[3] + startAction;
// Scale action to show content
if (centerPoints[3] + startAction > value && startAction < value) {
titles[0].style.transform = `scale(${
(value - startAction) / 100 > 1 ? 1 : (value - startAction) / 100
})`;
// titles[0].style.display = 'block';
img.style.transform = `scale(${
(value - startAction) / 100 > 1 ? 1 : (value - startAction) / 100
})`;
// img.style.display = 'block';
}
// Hide image & title if header visible
if (startAction > value) {
titles[0].style.transform = `scale(0)`;
img.style.transform = `scale(0)`;
}
// Hide first 'random text' when scroll above block
if (headerHeight > value) {
titles[1].style.transform = `translateX(0px)`;
titles[1].style.opacity = 0;
}
if (headerHeight < value) {
// Start scroll animation
const mainValue = value - headerHeight; // reset scroll to start from 0
titles[0].style.transform = `translateY(-${mainValue * speed}px)`;
// IMAGE BOUNCE
// Move to <==
if (centerPoints[0] > mainValue) {
img.style.transform = `translateX(-${
mainValue * (1 / setImageLimitMovement)
}px)`;
titles[1].style.transform = `translateX( ${
0 + mainValue / setTextLimitMovement
}px)`;
titles[1].style.opacity = mainValue / opacityRange;
return;
}
// Move to ==>
if (centerPoints[1] > mainValue) {
const moveTextToRight =
centerPoints[1] / setTextLimitMovement - textLimit;
const hideText = centerPoints[0] / opacityRange;
const checkDirection = Math.sign(
textLimit + (textLimit - mainValue / setTextLimitMovement)
);
const moveImageToRight =
(mainValue - centerPoints[0]) / setImageLimitMovement;
img.style.transform = `translateX(${
leftMoveLimitImg + moveImageToRight
}px)`;
if (checkDirection === -1) {
titles[1].style.opacity = 0;
titles[1].style.transform = `translateX(${0}px)`;
titles[2].style.opacity =
Math.abs(hideText - mainValue / opacityRange) - 1;
titles[2].style.transform = `translateX(${
moveTextToRight - mainValue / setTextLimitMovement
}px)`;
return;
}
if (checkDirection === 1) {
titles[1].style.opacity = 1 + (hideText - mainValue / opacityRange);
titles[1].style.transform = `translateX(${
textLimit + (textLimit - mainValue / setTextLimitMovement)
}px)`;
titles[2].style.opacity = 0;
titles[2].style.transform = `translateX(${0}px)`;
}
return;
}
// Move to <==
if (centerPoints[2] > mainValue) {
const moveTextToLeft =
centerPoints[2] / setTextLimitMovement - textLimit;
const hideText = centerPoints[1] / opacityRange;
const checkDirection = Math.sign(
moveTextToLeft - mainValue / setTextLimitMovement
);
const moveImageToLeft =
(-mainValue + centerPoints[1]) / setImageLimitMovement;
img.style.transform = `translateX(${
rightMoveLimitImg + moveImageToLeft
}px)`;
if (checkDirection === -1) {
titles[2].style.opacity = 0;
titles[2].style.transform = `translateX(${0}px)`;
titles[3].style.opacity =
Math.abs(hideText - mainValue / opacityRange) - 1;
titles[3].style.transform = `translateX(${Math.abs(
moveTextToLeft - mainValue / setTextLimitMovement
)}px)`;
}
if (checkDirection === 1) {
titles[2].style.opacity = 1 + (hideText - mainValue / opacityRange);
titles[2].style.transform = `translateX(-${
moveTextToLeft - mainValue / setTextLimitMovement
}px)`;
titles[3].style.opacity = 0;
titles[3].style.transform = `translateX(${0}px)`;
}
return;
}
// Move to ==>
if (centerPoints[3] > mainValue) {
const moveTextToRight =
centerPoints[3] / setTextLimitMovement - textLimit;
const hideText = centerPoints[2] / opacityRange;
const checkDirection = Math.sign(
moveTextToRight - mainValue / setTextLimitMovement
);
const moveImageToRight =
(mainValue - centerPoints[2]) / setImageLimitMovement;
img.style.transform = `translateX(${
leftMoveLimitImg + moveImageToRight
}px)`;
if (checkDirection === -1) {
titles[3].style.opacity = 0;
titles[3].style.transform = `translateX(${0}px)`;
// Hide image when scroll
const reduceOpacity = Math.abs(
(centerPoints[0] * 0.7 + (mainValue - centerPoints[3])) / 100
);
const checkReduceOpacity = Math.sign(
(centerPoints[0] * 0.7 + (mainValue - centerPoints[3])) / 100
);
if (checkReduceOpacity === -1) {
img.style.transform = `scale(${
reduceOpacity > 1 ? 1 : reduceOpacity
})`;
}
if (checkReduceOpacity === 1) {
img.style.transform = `scale(0)`;
}
}
//====
if (checkDirection === 1) {
titles[3].style.opacity = 1 + (hideText - mainValue / opacityRange);
titles[3].style.transform = `translateX(${
moveTextToRight - mainValue / setTextLimitMovement
}px)`;
}
return;
}
}
};
window.addEventListener('scroll', changeBackground);
return () => window.removeEventListener('scroll', changeBackground);
}, [screen]);
return (
<div className="App">
<div id="header" ref={headerRef}>
Header
</div>
<main ref={mainRef}>
<h1 id="title" className="titles">
Random Title
</h1>
<section id="block1" className="blocks">
block 1
</section>
<figure id="passport">
<img
alt="passport"
src="https://cdn.britannica.com/87/122087-050-1C269E8D/Cover-passport.jpg"
/>
</figure>
<h2 id="text1" className="titles text1">
Random Text 1
</h2>
<section id="block2" className="blocks">
block
</section>
<h2 id="text2" className="titles text2">
Random Text 2
</h2>
<section id="block3" className="blocks">
block
</section>
<h2 id="text3" className="titles text3">
Random Text 3
</h2>
<section id="block4" className="blocks">
block 4
</section>
</main>
{/* Stop Scrolling Animation */}
<div id="footer">Footer</div>
</div>
);
};
const rootElement = document.getElementById("root");
ReactDOM.render( <
App / > ,
rootElement
);
* {
padding: 0;
margin: 0;
box-sizing: border-box;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
.App {
font-family: sans-serif;
width: 100%;
background-color: hsl(220, 65%, 16%);
}
#header,
#footer {
height: 100vh;
display: grid;
place-items: center;
font-size: 4em;
color: aliceblue;
background-color: hsl(220, 65%, 45%);
}
main {
position: relative;
}
figure {
width: 280px;
height: max-content;
position: fixed;
inset: 0;
margin: auto;
z-index: 100;
}
img {
width: 100%;
}
.blocks {
height: 100vh;
display: flex;
position: relative;
grid-column: 1 / -1;
color: grey;
}
.titles {
width: max-content;
height: max-content;
position: fixed;
inset: 0;
margin: auto;
color: white;
z-index: 99;
}
h1 {
font-size: 3.5em;
}
h2 {
display: flex;
opacity: 0;
font-size: 2.5em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>
相关文章