2017-05-16 10 views
0

Reactアプリケーションを構築していますが、主な機能の1つはフルスクリーンのタイトルページです。ユーザーがタイトルページをスクロールすると、ページは自動的に下にスクロールし、ヘッダーバーは上にスティックされます。オーバーフローを戻すとすぐに、スクロールバーが表示され、ページ全体が約5ピクセル左に振れるので、私はここでボディのオーバーフローを隠してはいけません。Reactjsのスクロールを処理する

私はこの機能を多く見てきました。単一ページのWebデザインではかなり一般的です。しかし、私はそれを正しくするように見えることはできません。私はアプリがあなたのためにスクロールするまともなポイントになったが、自動スクロールの途中でスクロールしようとすると常にバグが出る。これは私が解決策を得ている最も近い:

import React, {Component} from 'react'; 
import Scroll from 'react-scroll'; 

class Header extends Component { 

constructor() { 
    super(); 
    this.state = { 
     scrolling: false, 
     inLogo: false, 
     sticky: "", 
     lastScrollPos: 0 
    } 
    /* Must bind to access 'this' */ 
    this.handleScroll = this.handleScroll.bind(this); 
    this.isScrollingDown = this.isScrollingDown.bind(this); 

    this.scroller = Scroll.animateScroll; 
} 

componentDidMount() { 
    window.addEventListener("scroll", this.handleScroll); 
    Scroll.Events.scrollEvent.register('end', function(to, element) { 
     this.state.scrolling = false; 
     if(!this.state.inLogo) { 
      this.setState({sticky: "sticky"}); 
     } 
    }.bind(this)); 

    if(window.pageYOffset < 150) { 
     this.state.inLogo = true; 
     this.scroller.scrollToTop(); 
    } else { 
     this.state.inLogo = false; 
     this.scroller.scrollTo(window.innerHeight); 
    } 
} 
componentDidUpdate() { 
    if(this.state.scrolling) { 
     if(this.state.inLogo) { 
      this.scroller.scrollToTop(); 
     } else { 
      this.scroller.scrollTo(window.innerHeight); 
     } 
    } 
} 

handleScroll(e) { 
    console.log(this.state.scrolling); 
    if(this.state.scrolling) { 
     return; 
    } 
    var scrollDown = this.isScrollingDown(); 
    var inLogo = this.isInLogo(); 
    if(inLogo) { 
     if(scrollDown) { 
      console.log("Scrolling down in logo"); 
      this.setState({ 
       scrolling: true, 
       inLogo: false 
      }); 
     } 
     if(!scrollDown) { 
      console.log("Scrolling up in logo"); 
      this.setState({ 
       scrolling: true, 
       inLogo: true, 
       sticky: "" 
      }); 
     } 
    } 
} 

isScrollingDown() { 
    var scrollingDown = window.pageYOffset > this.state.lastScrollPos; 
    this.state.lastScrollPos = window.pageYOffset; 
    return scrollingDown; 
} 

isInLogo() { 
    return window.pageYOffset > 150 && window.pageYOffset < window.innerHeight; 
} 

render() { 
    return (
     <div id="app-header" className={"header "+this.state.sticky}> 
      <div className="header-filler"></div> 
      <a href="#contactUs"><button>Contact Us</button></a> 
      <a href="#firstSection"><button>First</button></a> 
     </div> 
    ); 
} 
} 

ここでの問題は、あなたが自動スクロールの途中でスクロールするとき、react-scroll"end"スクロールイベントが発生していることです。したがって、"end"スクロールのコールバックは、this.state.scrollingをfalseに設定します。今度は、それが偽であるので、スクロールが処理され、I setState()が再び表示され、ヘッダーバーがスティッキーになる可能性があります。

ボトムライン:理想的なソリューションは、それがスクロール開始時にcomponentDidUpdateでスクロールを無効にし、"end"イベントハンドラでそれを再度有効にすることです。このソリューションの問題は、ユーザーが自動スクロールを中断したときに呼び出されるイベントハンドラです。

最後に、私はスクロールを無効/有効にするためにstackoverflowのいくつかのメソッドを見つけましたが、"end"イベント処理の問題を助けるように見えなかったので、それらを取り出しました。ハンドラが起動されたときにスクロールを再び有効にするだけです。

質問をするには、私はこれを明確に説明することが本当に難しいです。

答えて

0

解決策が見つかりました。スクロールが実際に終了する前に呼び出された場合、私は'end'イベントハンドラのスクロールを基本的に「続行」しなければなりませんでした。更新されたコードは次のとおりです。

import React, { Component } from 'react'; 

インポートスクロール 'react-scroll';

クラスヘッダー{

constructor() { 
    super(); 
    //scroll direction: (1) - down, (2) - up 
    this.state = { 
     scrolling: false, 
     inLogo: false, 
     sticky: "", 
     lastScrollPos: 0 
    } 
    /* Must bind to access 'this' */ 
    this.handleScroll = this.handleScroll.bind(this); 
    this.scroller = Scroll.animateScroll; 
    this.isScrollingDown = this.isScrollingDown.bind(this); 
} 

componentDidMount() { 
    window.addEventListener("scroll", this.handleScroll); 
    Scroll.Events.scrollEvent.register('end', function() { 
     if(window.pageYOffset == 0) { 
      console.log("End: "+window.pageYOffset); 
      this.setState({sticky: "", scrolling: false}); 
     } 
     else if(window.pageYOffset == window.innerHeight) { 
      console.log("End: "+window.pageYOffset); 
      this.setState({sticky: "sticky", scrolling: false}); 
     } else { 
      if(this.state.inLogo) { 
       this.scroller.scrollToTop(); 
      } else { 
       this.scroller.scrollTo(window.innerHeight); 
      } 
     } 
    }.bind(this)); 

    if(window.pageYOffset < 150) { 
     this.state.inLogo = true; 
     this.scroller.scrollTo(0); 
    } else { 
     this.state.inLogo = false; 
     this.scroller.scrollTo(window.innerHeight); 
    } 
} 
componentDidUpdate() { 
    if(this.state.scrolling) { 
     if(this.state.inLogo) { 
      this.scroller.scrollToTop(); 
     } else { 
      this.scroller.scrollTo(window.innerHeight); 
     } 
    } 
} 

handleScroll(e) { 
    console.log(this.state.scrolling); 
    if(this.state.scrolling) { 
     return; 
    } 
    var scrollDown = this.isScrollingDown(); 
    var inLogo = this.isInLogo(); 
    if(inLogo) { 
     if(scrollDown) { 
      console.log("Scrolling down in logo"); 
      this.setState({ 
       scrolling: true, 
       inLogo: false 
      }); 
     } 
     if(!scrollDown) { 
      console.log("Scrolling up in logo"); 
      this.setState({ 
       scrolling: true, 
       inLogo: true, 
       sticky: "" 
      }); 
     } 
    } 
} 

isScrollingDown() { 
    var scrollingDown = window.pageYOffset > this.state.lastScrollPos; 
    this.state.lastScrollPos = window.pageYOffset; 
    return scrollingDown; 
} 

isInLogo() { 
    return window.pageYOffset > 150 && window.pageYOffset < window.innerHeight - 5; 
} 
コンポーネントを拡張します
関連する問題