改变div的offsetTop

时间:2016-09-27 09:11:17

标签: javascript html reactjs

我正在尝试在我的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?

The portion in red bounds needs to stick

1 个答案:

答案 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);
}