2016-04-28 10 views
11

Mam problem podczas przechodzenia do innej strony, jego położenie pozostanie takie jak poprzednia strona. Więc nie będzie automatycznie przewijać do góry. Próbowałem również użyć window.scrollTo(0, 0) na routerze onChange. Użyłem również scrollBehavior, aby naprawić ten problem, ale nie działa. Wszelkie sugestie na ten temat?router reagujący przewijaj do góry przy każdym przejściu

+0

mógłbyś nie robić logikę w 'componentDidMount' składnika nowa trasa jest? – Kujira

+0

po prostu dodaj 'document.body.scrollTop = 0;' w 'componentDidMount' składnika, który przenosisz do –

+0

@Kujira już dodałem scrollTo wewnątrz componentDidMount(), ale nie działa. –

Odpowiedz

-1

Znalazłem, że działa ReactDOM.findDomNode(this).scrollIntoView(). Umieściłem go wewnątrz componentDidMount().

+0

to nieudokumentowane pliki wewnętrzne, które mogą ulec zmianie bez powiadomienia, a kod przestanie działać. –

+0

Niewłaściwe podejście –

20
<Router onUpdate={() => window.scrollTo(0, 0)} history={createBrowserHistory()}> 
    ... 
</Router> 

Jeśli to nie działa, powinieneś znaleźć przyczynę. Również wewnątrz componentDidMount

document.body.scrollTop = 0; 
// or 
window.scrollTo(0,0); 

można użyć:

componentDidUpdate() { 
    window.scrollTo(0,0); 
} 

można dodać flagę jak "przewijane = false", a następnie w aktualizacji:

componentDidUpdate() { 
    if(this.scrolled === false){ 
    window.scrollTo(0,0); 
    scrolled = true; 
    } 
} 
+1

this.getDomNode jest przestarzałe. Tak używam ReactDOM.findDomNode() .. –

+0

Mam zaktualizowaną odpowiedź bez w/w getDomNode w ogóle, ponieważ w rzeczywistości nigdy nie musiałem używać go do przewijania do góry. Właśnie użyłem 'window.scrollTo (0,0);' –

+2

'hook onUpdate' jest przestarzałe w routerze reagowania v4 - po prostu chcę wskazać na to –

-3

To jest hacky (ale działa): Właśnie dodam

window.scrollTo (0,0);

do renderowania();

+0

, dzięki czemu będzie przewijany za każdym razem, gdy zmiany stanu i ponowne renderowanie ma miejsce, a nie po zmianie nawigacji. Po prostu sprawdź moją odpowiedź –

4

Miałem ten sam problem z moją aplikacją. Wykorzystanie poniższego fragmentu kodu pomogło mi przewinąć do góry strony po kliknięciu następnego przycisku.

<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}> 
... 
</Router> 

Jednak problem nadal występował w przeglądarce z powrotem. Po wielu próbach zdałem sobie sprawę, że dzieje się tak z powodu obiektu historii okna przeglądarki, który ma właściwość scrollRestoration, która została ustawiona na auto. Ustawienie ręczne rozwiązało mój problem.

function scrollToTop() { 
    window.scrollTo(0, 0) 
    if ('scrollRestoration' in history) { 
     history.scrollRestoration = 'manual'; 
    } 
} 

<Router onUpdate= {scrollToTop} history={browserHistory}> 
.... 
</Router> 
11

Na reakcji routerem v4, jest tu stworzenie reagują app, że osiąga się odtworzenie przewijania: http://router-scroll-top.surge.sh/.

W tym celu można utworzyć ozdobić Route składowe i dźwigni cyklu życia metod osiągnięcia:

import React, { Component } from 'react'; 
import { Route, withRouter } from 'react-router-dom'; 

class ScrollToTopRoute extends Component { 
    componentDidUpdate(prevProps) { 
    if (this.props.path === this.props.location.pathname && this.props.location.pathname !== prevProps.location.pathname) { 
     window.scrollTo(0, 0) 
    } 
    } 

    render() { 
    const { component: Component, ...rest } = this.props; 

    return <Route {...rest} render={props => (<Component {...props} />)} />; 
    } 
} 

export default withRouter(ScrollToTopRoute); 

On the componentDidUpdate Możemy sprawdzić, kiedy lokalizacja zmiany ścieżka i dopasować go do path rekwizyt, a jeśli te spełnione, przywróć przewijanie okna.

Co jest fajne w tym podejściu, to że możemy mieć trasy, które przywracają przewijanie i trasy, które nie przywracają przewijania.

Oto App.js przykładem tego, jak można użyć powyższego:

import React, { Component } from 'react'; 
import { BrowserRouter as Router, Route, Link } from 'react-router-dom'; 
import Lorem from 'react-lorem-component'; 
import ScrollToTopRoute from './ScrollToTopRoute'; 
import './App.css'; 

const Home =() => (
    <div className="App-page"> 
    <h2>Home</h2> 
    <Lorem count={12} seed={12} /> 
    </div> 
); 

const About =() => (
    <div className="App-page"> 
    <h2>About</h2> 
    <Lorem count={30} seed={4} /> 
    </div> 
); 

const AnotherPage =() => (
    <div className="App-page"> 
    <h2>This is just Another Page</h2> 
    <Lorem count={12} seed={45} /> 
    </div> 
); 

class App extends Component { 
    render() { 
    return (
     <Router> 
     <div className="App"> 
      <div className="App-header"> 
      <ul className="App-nav"> 
       <li><Link to="/">Home</Link></li> 
       <li><Link to="/about">About</Link></li> 
       <li><Link to="/another-page">Another Page</Link></li> 
      </ul> 
      </div> 
      <Route exact path="/" component={Home} /> 
      <ScrollToTopRoute path="/about" component={About} /> 
      <ScrollToTopRoute path="/another-page" component={AnotherPage} /> 
     </div> 
     </Router> 
    ); 
    } 
} 

export default App; 

Z powyższego kodu, co jest interesujące zwrócić uwagę jest to, że tylko podczas nawigowania do /about lub /another-page przewijania do początku działania będą być przygotowanym. Jednak po przejściu na / nie nastąpi przywracanie przewijania.

Cały codebase można znaleźć tutaj: https://github.com/rizedr/react-router-scroll-top

+1

Właśnie tego szukałem! Musiałem dodać scrollTo w componentDidMount of ScrollToTopRoute, ponieważ moje trasy zostały zawinięte w komponent Switch (usunąłem również, jeśli chciałem, aby był uruchamiany na każdym z nich). – tocallaghan

+0

W renderowaniu twojego ScrollToTopRoute, nie masz t musisz określić render = {rekwizyty => ()}. Samo użycie {... reszta} na trasie zadziała. – Finickyflame

7

Dokumentacja React Router v4 zawiera code samples dla przywrócenia przewijania. Oto ich pierwsze przykładowy kod, który służy jako teren całego rozwiązania dla „przewinąć do góry”, gdy strona jest nawigacja do:

class ScrollToTop extends Component { 
    componentDidUpdate(prevProps) { 
    if (this.props.location !== prevProps.location) { 
     window.scrollTo(0, 0) 
    } 
    } 

    render() { 
    return this.props.children 
    } 
} 

export default withRouter(ScrollToTop) 

Następnie czyni go w górnej części Twojej aplikacji, ale poniżej Router:

const App =() => (
    <Router> 
    <ScrollToTop> 
     <App/> 
    </ScrollToTop> 
    </Router> 
) 

// or just render it bare anywhere you want, but just one :) 
<ScrollToTop/> 

^ copied directly from the documentation

Oczywiście działa to w większości przypadków, ale jest więcej o tym, jak radzić sobie z kartami interfejsów i dlaczego rodzajowe rozwiązanie nie został wdrożony.

1

Napisałem komponent wyższego rzędu o nazwie withScrollToTop. Ten HOC odbywa się w dwóch flag:

  • onComponentWillMount - Niezależnie od tego, aby przewinąć do góry na nawigacji (componentWillMount)
  • onComponentDidUpdate - Niezależnie od tego, aby przewinąć do góry po aktualizacji (componentDidUpdate). Ta flaga jest niezbędna w przypadkach, gdy komponent nie jest odmontowany, ale zdarzenie nawigacyjne występuje, na przykład, od /users/1 do /users/2.

// @flow 
import type { Location } from 'react-router-dom'; 
import type { ComponentType } from 'react'; 

import React, { Component } from 'react'; 
import { withRouter } from 'react-router-dom'; 

type Props = { 
    location: Location, 
}; 

type Options = { 
    onComponentWillMount?: boolean, 
    onComponentDidUpdate?: boolean, 
}; 

const defaultOptions: Options = { 
    onComponentWillMount: true, 
    onComponentDidUpdate: true, 
}; 

function scrollToTop() { 
    window.scrollTo(0, 0); 
} 

const withScrollToTop = (WrappedComponent: ComponentType, options: Options = defaultOptions) => { 
    return class withScrollToTopComponent extends Component<Props> { 
    props: Props; 

    componentWillMount() { 
     if (options.onComponentWillMount) { 
     scrollToTop(); 
     } 
    } 

    componentDidUpdate(prevProps: Props) { 
     if (options.onComponentDidUpdate && 
     this.props.location.pathname !== prevProps.location.pathname) { 
     scrollToTop(); 
     } 
    } 

    render() { 
     return <WrappedComponent {...this.props} />; 
    } 
    }; 
}; 

export default (WrappedComponent: ComponentType, options?: Options) => { 
    return withRouter(withScrollToTop(WrappedComponent, options)); 
}; 

Aby go użyć:

import withScrollToTop from './withScrollToTop'; 

function MyComponent() { ... } 

export default withScrollToTop(MyComponent); 
Powiązane problemy