react spring视差-滚动视差时无法注册onScroll事件



我使用反作用弹簧的视差组件来实现父组件上的视差效果。在这个组件中,视差中有一组背景形状

<Parallax ref={parallaxRef} pages={7.465} scrolling={props.stageData.contractActive && !isMobile ? true : false}>
<div className="desktop-bg-shapes">
<ParallaxLayer offset={0} speed={0.5}>
<span className="rectangle bg-rectangle rectangle-1 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={0} speed={0.5}>
<span className="rectangle bg-rectangle rectangle-2 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={0} speed={0.2}>
<span className="rectangle bg-rectangle rectangle-3 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={1.3} speed={0.6}>
<span className="rectangle bg-rectangle rectangle-4 light-blue"></span>
</ParallaxLayer>
<ParallaxLayer offset={4} speed={0.4}>
<span className="rectangle bg-rectangle rectangle-5 blue"></span>
</ParallaxLayer>
<ParallaxLayer offset={6.7} speed={0.8}>
<span className="rectangle bg-rectangle rectangle-6 light-blue"></span>
</ParallaxLayer>
</div>

当我滚动页面的主要部分时,这些都在移动,这是以页面为中心的内容(左右两侧是滚动该内容时移动的上述形状(,也在父组件的视差范围内

<ParallaxLayer ref={parallaxMainLayer} offset={0} speed={0}>
<div className="viewport desktop">
CONTENT HERE
....etc 

视差效果起作用。但另一种影响已经停止了。以前,当用户向下滚动页面时,标题会根据用户滚动的位置而改变颜色。然而,现在onScroll事件没有启动,我现在确定如何让它启动

这是上述父组件中的标题

<Header readCarefulStart={readCarefulStart} agreeSect={agreeSect}/>

我将上面的ref传递给Header组件本身中的getBoundingClientRect((。我正在使用useEffect在标题组件中注册onScroll,就像一样

useEffect(() => {
const handleScroll = (event) => {
// fill info
if (props.readCarefulStart.current.getBoundingClientRect().top > 150)
props.activeFillInfo()

// read carefully
else if (props.readCarefulStart.current.getBoundingClientRect().top <= 150 && props.readCarefulStart.current.getBoundingClientRect().top >= -3464 && props.agreeSect.current.getBoundingClientRect().top === 0) 
props.activeReadCarefully()

// signature 
else if (props.readCarefulStart.current.getBoundingClientRect().top < -3464) 
props.activeSignature() 

})
}
window.addEventListener('scroll', handleScroll);
return () => document.removeEventListener('scroll', handleScroll);
}, [])

以前标题是基于onScroll更改颜色的,但现在当我控制台.log(事件(时,这个事件没有注册。为什么会这样?

function App(props){
return (
<Header readCarefulStart={readCarefulStart} agreeSect={agreeSect}/>
<Parallax ref={parallaxRef} pages={7.465} scrolling={props.stageData.contractActive && !isMobile ? true : false}>
<div className="desktop-bg-shapes">
<ParallaxLayer offset={0} speed={0.5}>
<span className="rectangle bg-rectangle rectangle-1 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={0} speed={0.5}>
<span className="rectangle bg-rectangle rectangle-2 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={0} speed={0.2}>
<span className="rectangle bg-rectangle rectangle-3 orange"></span>
</ParallaxLayer>
<ParallaxLayer offset={1.3} speed={0.6}>
<span className="rectangle bg-rectangle rectangle-4 light-blue"></span>
</ParallaxLayer>
<ParallaxLayer offset={4} speed={0.4}>
<span className="rectangle bg-rectangle rectangle-5 blue"></span>
</ParallaxLayer>
<ParallaxLayer offset={6.7} speed={0.8}>
<span className="rectangle bg-rectangle rectangle-6 light-blue"></span>
</ParallaxLayer>
</div>
<ParallaxLayer ref={parallaxMainLayer} offset={0} speed={0}>
<div className="viewport desktop">
CONTENT HERE
....etc 
</div>
</ParallaxLayer>
</Parallax>
)
}
function Header(props) {
useEffect(() => {
const handleScroll = (event) => {
// fill info
if (props.readCarefulStart.current.getBoundingClientRect().top > 150)
props.activeFillInfo()
// read carefully
else if (props.readCarefulStart.current.getBoundingClientRect().top <= 150 && props.readCarefulStart.current.getBoundingClientRect().top >= -3464 && props.agreeSect.current.getBoundingClientRect().top === 0) 
props.activeReadCarefully()
// signature 
else if (props.readCarefulStart.current.getBoundingClientRect().top < -3464) 
props.activeSignature() 
})
}
window.addEventListener('scroll', handleScroll);
return () => document.removeEventListener('scroll', handleScroll);
}, [])
return(
<header>
<div className="viewport">
<div className="inner">
<nav>
<ul>
<li className='start-header'><span className="num-circle">1</span><span className="text">Start</span></li>        
<li className='fill-info'><span className="num-circle">2</span><span className="text">Fill in information</span></li>                    
<li className='read-carefully'><span className="num-circle">3</span><span className="text">Read Carefully</span></li>                   
<li className='sign'><span className="num-circle">4</span><span className="text">Sign</span></li>
<li className='agreement'><span className="num-circle">5</span><span className="text">New agreement</span></li>     
</ul>
</nav>
</div>
</div>
</header>
)
}

*edit在末尾的一个部分添加了所有代码

一个更巧妙的解决方案是直接从Parallax组件的ref设置监听器,而不是使用querySelector。

示例:

const Test = () => {
const parallaxRef = useRef()
const onScroll = () =>
console.log(parallaxRef.current.current / parallaxRef.current.space)
useEffect(() => {
if (!parallaxRef.current || !parallaxRef.current.container) return
parallaxRef.current.container.onscroll = onScroll
})
return (
<div>
<Parallax pages={3} ref={parallaxRef}>
<ParallaxLayer offset={0} speed={0.5}>
<span onClick={() => parallaxRef.current.scrollTo(1)}>
Layers can contain anything
</span>
</ParallaxLayer>
...
</Parallax>
</div>
)
}

从react spring Parallax的源代码中可以看到,ref包含对组件创建的两个div元素的引用。

根据其react spring文档,

Parallax组件创建一个可滚动的容器,其中可以放置ParallaxLayers或React。其唯一直接子级是ParallaxLayer的片段。由于Parallax是一个可滚动的容器,所有滚动事件都是从容器本身触发的,因此,在窗口上侦听滚动将不起作用。但是,如果您想附加其他事件,可以使用ref.current.contain

并且在我遵循它的步骤之后,以下是我得到的

const ref = useRef<IParallax>();
const scrollListener = () => {
const handleWheelEvent = () => {
const {container, current} = ref.current;
const scrollpercent = current / (container.current.scrollHeight - window.innerHeight)
console.log(scrollpercent);
};
window.addEventListener('wheel', handleWheelEvent);
return () => {
window.removeEventListener('wheel', handleWheelEvent);
};
};
useEffect(scrollListener, []);
return (
<Parallax className={styles['parallax-pane']} pages={5} ref={ref}>
...

这对我来说很有效:

const parallaxRef = useRef<IParallax>(null)
function scrollListener() {
const container = parallaxRef.current?.container
.current as HTMLDivElement
container.onscroll = () => {
setScrollTop(parallaxRef.current?.current as number)
}
return () => {
container.onscroll = null
}
}

useEffect(scrollListener, [])

不幸的是,Marvin的解决方案在移动设备上不起作用。

我自己修复了这个

所以问题是,我在窗口中添加了一个事件监听器,而不是视差

window.addEventListener('scroll', handleScroll);

所以我在主视差组件上添加了一个类。顶部级别的视差创建了两个div,因此您需要将代码中视差的直接子级(祖父母(之上的两个级别作为目标

useEffect(() => {
document.querySelector('div.classNameOfChildOfParallax').parentElement.classList.add('parallax-child')
document.querySelector('div.parallax-child').parentElement.classList.add('parallax-main')
}, []) 

然后在标题中进行

document.querySelector('div.parallax-main').addEventListener('scroll', handleScroll);