我正在构建一个 React 应用程序,我想有一个全局 CSS 类,当组件出现在视口中时,该类用于淡入淡出。
jQuery
使用jQuery,我可能会做这样的事情:
const windowHeight = (window.innerHeight || document.documentElement.clientHeight);
const windowWidth = (window.innerWidth || document.documentElement.clientWidth);
isInViewport(el) {
const rect = el.getBoundingClientRect();
const vertInView = (rect.top <= windowHeight) && ((rect.top + rect.height) >= 0);
const horInView = (rect.left <= windowWidth) && ((rect.left + rect.width) >= 0);
return (vertInView && horInView);
};
$(window).scroll(function(e) {
$('.animate').each(function() {
if(isInViewport($(this)[0])) {
$(this).addClass('animate--active');
}
});
});
滚动时,我会使用animate
类检查每个元素,如果该元素在视口中,请将animate--active
类添加到其中,这将淡入。
反应
在 React 中,我将我的isInViewport()
函数移动到全局Helpers.js
文件中,以便任何组件都可以使用它,但我不得不将滚动事件和动态类添加到每个组件,这会产生大量重复的代码。例如:
import { isInViewport } from './Helpers.js';
function MyComponent(props) {
const [inViewport, setInViewport] = useState(false);
const myComponentRef = useRef();
function handleScroll(e) {
setInViewport(isInViewport(myComponentRef.current));
}
useEffect(() => {
window.addEventListener('scroll', handleScroll);
// unmount
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
const classes = (inViewport) ? 'animate animate--active' : 'animate';
return (
<section className={classes} ref={myComponentRef}>
</section>
);
}
据我所知,这将是 React 执行此操作的方式,这确实有效,但同样,这意味着每个组件都需要自己的状态变量、滚动事件和类声明,这加起来会有很多重复。有没有更好的方法
?自定义钩子, 自定义钩子, 自定义钩
子import { isInViewport } from './Helpers.js';
function useIsInViewPort(ref) {
const [inViewport, setInViewport] = React.useState(false);
function handleScroll(e) {
setInViewport(isInViewport(ref.current));
}
React.useEffect(() => {
window.addEventListener('scroll', handleScroll);
// unmount
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, []);
return inViewport;
}
function Acmp(props) {
const ref = React.useRef();
const inViewport = useIsInViewPort(ref);
const classes = (inViewport) ? 'animate animate--active' : 'animate';
return (
<section className={classes} ref={ref}>
</section>
);
}
function Bcmp(props) {
const ref = React.useRef();
const inViewport = useIsInViewPort(ref);
return (
<section className={classes} ref={ref}>
</section>
);
}