我正在尝试在我的react app组件中实现sticky navbar to top on scrolling past it。
componentDidMount(){
var self = this;
let $ribbonEl = ReactDOM.findDOMNode(self.refs.ribbon);
setTimeout(function(){
let ribbonElOffsetTop = $ribbonEl.offsetTop;
let $body = document.body;
stickyScrollHandler = function (event) {
console.log($body.scrollTop, ribbonElOffsetTop);
if($body.scrollTop > ribbonElOffsetTop){
$ribbonEl.style.position = 'fixed';
$ribbonEl.style.top = 0;
}else{
$ribbonEl.style.position = 'absolute';
$ribbonEl.style.top = 'initial';
}
}
document.addEventListener('scroll', stickyScrollHandler);
}, 1000)
}
问题是我需要在超时内包装并附加我的滚动处理程序,并希望它在1秒内获得正确的offsetTop。因为有时需要花费时间来加载像图像这样的动态元素,其高度是动态的,并且只能在加载时决定。所以我最终得到一个较低的offsetTop说340px而不是411px的右侧offsetTop,这会在UI中产生错误。
那么,实现同样目标的正确方法是什么?如何检测其offsetTop中的更改并获取最终的offsetTop以附加scrollHandler?
答案 0 :(得分:0)
您现在正在做的是提前猜测您的页面何时加载,以便您可以执行逻辑。所以你放一个timeout()
来推迟在未来1s时的逻辑。这种方法的问题就像您的问题中所揭示的那样:如果您的页面打印时间超过1秒会发生什么?
我会说你应该依靠component lifecycle
而不是setTimeout
来揭露你的逻辑。
从本质上讲,你想要实现的目标可以用简单的英语写成,如下所示:“当我的组件被安装时,做我的逻辑”。 现在,您可以直接遵循:“当我的组件更新时,再次执行我的逻辑”。
componentDidMount(){
// exec func()
}
componentDidUpdate(){
// exec func()
}
这样,无论发生什么,都可以确保您的逻辑得到刷新。
最后,为了保持DRY
,你还希望将你的逻辑/功能放入其独立的底池中:
stickyScrollHandler(){
// your logic here
}
这样,快速代码看起来像:
stickyScrollHandler(){
let $ribbon = ReactDOM.findDOMNode(self.refs.ribbon);
let $body = document.body;
console.log($body.scrollTop, $ribbon.OffsetTop);
if($body.scrollTop > $ribbon.OffsetTop){
$ribbon.style.position = 'fixed';
$ribbon.style.top = 0;
} else {
$ribbon.style.position = 'absolute';
$ribbon.style.top = 'initial';
}
}
componentDidMount(){
document.addEventListener('scroll', stickyScrollHandler);
}
componentDidUpdate(){
this.stickyScrollHandler()
}
componentWillUNMount(){
document.removeEventListener('scroll', stickyScrollHandler);
}