[英]How to make a React component fade in on scroll using IntersectionObserver, but only once?
I am trying to give components a fade-in effect in React when the user scrolls, but I want the fade-in effect to only happen the first time the element moves into the viewport.当用户滚动时,我试图在 React 中为组件提供淡入效果,但我希望淡入效果仅在元素第一次移动到视口时发生。
Currently, the code I am using causes a fade-in every time the element moves into the viewport, so they are constantly fading in and out.目前,每次元素移动到视口时,我使用的代码都会导致淡入,因此它们不断地淡入淡出。
Here is my fade-in component:这是我的淡入组件:
import React, {useState, useRef, useEffect} from 'react';
import './styles/FadeInSection.css';
export default function FadeInSection(props) {
const [isVisible, setVisible] = useState(true);
const domRef = React.useRef();
useEffect(() => {
const observer = new IntersectionObserver(entries => {
entries.forEach(entry => setVisible(entry.isIntersecting));
});
observer.observe(domRef.current);
return () => observer.unobserve(domRef.current);
}, []);
return (
<div ref={ domRef } className={ `fade-in-section ${ isVisible ? 'is-visible' : '' }` }>
{ props.children }
</div>
)
}
And these are the styles I'm using:这些是我正在使用的样式:
.fade-in-section {
opacity: 0;
transform: translateY(20vh);
isibility: hidden;
transition: opacity 0.2s ease-out, transform 0.6s ease-out;
will-change: opacity, visibility;
}
.fade-in-section.is-visible {
opacity: 1;
transform: none;
visibility: visible;
display: flex;
}
Here is my website, which keeps fading components in and out, offering a terrible experience:这是我的网站,它不断地淡入淡出组件,提供了糟糕的体验:
And this is the desired effect:这是想要的效果:
How can I achieve the desired effect?我怎样才能达到预期的效果?
Here is a link to the code sandbox to test it: Code sandbox link这是代码沙箱的链接以进行测试: 代码沙箱链接
You only need to call setVisible
if entry.isIntersecting
is true
, so simply replace:您只需要在entry.isIntersecting
为true
调用setVisible
,因此只需替换:
setVisible(entry.isIntersecting);
With:和:
entry.isIntersecting && setVisible(true);
This way, once an entry has already been marked as visible, it won't be unmarked, even if you scroll back up, so the element goes out of the viewport, and entry.isIntersecting
becomes false
again.这样,一旦一个条目已经被标记为可见,即使您向上滚动,它也不会被取消标记,因此该元素离开视口,并且entry.isIntersecting
再次变为false
。
Actually, you can even call observer.unobserve
at that point, as you don't care anymore.实际上,此时您甚至可以调用observer.unobserve
,因为您不再关心了。
const FadeInSection = ({ children, }) => { const domRef = React.useRef(); const [isVisible, setVisible] = React.useState(false); React.useEffect(() => { const observer = new IntersectionObserver(entries => { // In your case there's only one element to observe: if (entries[0].isIntersecting) { // Not possible to set it back to false like this: setVisible(true); // No need to keep observing: observer.unobserve(domRef.current); } }); observer.observe(domRef.current); return () => observer.unobserve(domRef.current); }, []); return (<section ref={ domRef } className={ isVisible ? ' is-visible' : '' }>{ children }</section>); }; const App = () => { const items = [1, 2, 3, 4, 5, 6, 7, 8].map(number => ( <FadeInSection key={ number }>Section { number }</FadeInSection> )); return (<main>{ items }</main>); } ReactDOM.render(<App />, document.querySelector('#app'));
body { font-family: monospace; margin: 0; } section { padding: 16px; margin: 16px; box-shadow: 0 0 8px rgba(0, 0, 0, .125); height: 64px; opacity: 0; transform: translate(0, 50%); visibility: hidden; transition: opacity 300ms ease-out, transform 300ms ease-out; will-change: opacity, visibility; } .is-visible { opacity: 1; transform: none; visibility: visible; display: flex; }
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js"></script> <div id="app"></div>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.