如何在react中创建一个动画平滑的粘头



我有一个标题,我想变成一个粘头,一旦用户开始向下滚动页面,它也应该是平滑的,不只是跳下屏幕,我不想只是使用position: fixed只是把它粘到屏幕的顶部。这也是在nextjs应用程序中。

const Header = () => {
useEffect(() => {
window.onscroll = () => {
document.getElementById('header').classList.add('sticky')
// what else do I need here
}
}, [])
}
...
#header {
transition: top 1s;
}
#header.sticky {
position: sticky;
// what else do I need here
}

你需要做几件事。

let timeout
let scroll = 0
const Header = () => {
useEffect(() => {
window.onscroll = () => {
if (timeout) {
clearTimeout(timeout)
}
timeout = setTimeout(() => {
if (scroll >= window.scrollY && window.scrollY > 10) {
document.getElementById('header').classList.add('sticky')
} else {
document.getElementById('header').classList.remove('sticky')
}
scroll = window.scrollY
}, 10)
}
}, [])
}
...
#header {
top: -100px;
transition: top 0.5s ease-in-out;
}
#header.sticky {
position: sticky;
top: 0;
}
  • 在滚动时创建一个窗口事件监听器,如果它是一个服务器端渲染应用程序,如在nextjs中使用useEffect,否则你可以不使用。
  • 指定或删除滚动上的粘滞类,您可以使用document.getElementById或在标题组件上使用useRef来完成此操作。
  • 使用一个超时,这样事件不会在每次滚动时触发,而应该在滚动停止后10ms触发。
  • 跟踪滚动变量,这样你就可以弄清楚用户是向上还是向下滚动,这样你就可以只在他们向上滚动时显示标题。
  • 作为一个小技巧,你可以将初始标题位置顶部设置为-100px,如果标题上实际上没有任何position: absolute,position: fixedposition: sticky,这将没有效果。然后,当你应用类粘性时,你将顶部值更改为0,这将创建一个标题突然"出现"的效果。从顶部向下滚动。这就是创建动画的方法。

自我回答的解决方案似乎比必要的工作要多得多;一个纯CSS解决方案应该就足够了,除非我误解了需求。见下文:

const Header = () => {
return (
<div className="header">header content here</div>
);
};

const Content = () => {
return (
<div className="content">
<h1>Hello</h1>
<p>How are you?</p>
<p>Lovely weather were having, no?</p>
<p>The quick brown fox jumped over the lazy dog</p>
<p>Every Good Boy Does Fine</p>
<p>Mary's violet eyes made john stay up nights proposing</p>
<p>FOIL</p>
<p>How are you?</p>
<p>Lovely weather were having, no?</p>
<p>The quick brown fox jumped over the lazy dog</p>
<p>Every Good Boy Does Fine</p>
<p>Mary's violet eyes made john stay up nights proposing</p>
<p>FOIL</p>
<p>How are you?</p>
<p>Lovely weather were having, no?</p>
<p>The quick brown fox jumped over the lazy dog</p>
<p>Every Good Boy Does Fine</p>
<p>Mary's violet eyes made john stay up nights proposing</p>
<p>FOIL</p>
</div>
);
};
const App = () => {
return (
<div>
<Header />
<Content />
</div>
);
};
// Render it
ReactDOM.render(
<App />,
document.getElementById("react")
);
body {
padding: 0;
margin: 0;
}
.header {
background-color: pink;
padding: 1rem;
position: sticky;
top: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

最新更新