2016-04-28 2 views
11

У меня проблема при переходе на другую страницу, ее позиция останется прежней. Таким образом, он не будет автоматически прокручиваться вверх. Я также пытался использовать window.scrollTo(0, 0) на маршрутизаторе onChange. Я также использовал scrollBehavior, чтобы исправить эту проблему, но она не работала. Любое предложение об этом?Реактивный маршрутизатор прокручивается вверх на каждом переходе

+0

Не могли бы вы не делать логику в 'componentDidMount' компонента нового маршрута? – Kujira

+0

просто добавьте 'document.body.scrollTop = 0;' в 'componentDidMount' компонента, который вы переходите на –

+0

@ Kujira. Я уже добавил scrollTo внутри componentDidMount(), но он не работал. –

ответ

-1

Я нашел, что работает ReactDOM.findDomNode(this).scrollIntoView(). Я разместил его внутри componentDidMount().

+0

Это недокументированные внутренние вещи, которые могут измениться без уведомления, и ваш код перестанет работать. –

+0

Нехороший подход –

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

Если он не работает, вы должны найти причину. Также внутри componentDidMount

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

вы можете использовать:

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

можно добавить флаг как "прокручивается = ложь", а затем в обновлении:

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

this.getDomNode устарел. Поэтому я использую ReactDOM.findDomNode() .. –

+0

Я обновил ответ без getDomNode, потому что на самом деле мне никогда не приходилось использовать его для прокрутки вверх. Я просто использую 'window.scrollTo (0,0);' –

+2

'onUpdate' крючок устарел в response-router v4 - просто хочу указать, что это –

-3

Это Hacky (но работает): Я просто добавлю

window.scrollTo (0,0);

to render();

+0

, чтобы он прокручивал при каждом изменении состояния и повторной визуализации, а не при изменении навигации. Просто проверьте мой ответ –

4

У меня была такая же проблема с моим приложением. Используя нижеприведенный фрагмент кода, я помог мне прокрутить вверх страницы по щелчку следующей кнопки.

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

Однако проблема по-прежнему сохраняется в браузере. После многих испытаний выяснилось, что это произошло из-за объекта истории окна браузера, который имеет свойство scrollRestoration, которое было настроено на auto.Setting this to manual решил мою проблему.

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

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

Для реагировать маршрутизаторы v4, вот создать реагирующий-приложение, которое обеспечивает восстановление прокрутки: http://router-scroll-top.surge.sh/.

Для достижения этой цели вы можете создать декорировать Route компонентов и использовать жизненный цикл методов:

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 мы можем проверить, когда изменяется имя пути определения местоположения и сопоставьте его path опоры и, если таковые удовлетворены, восстановите прокрутку окна.

Что круто в этом подходе, так это то, что у нас могут быть маршруты, которые восстанавливают прокрутку и маршруты, которые не восстанавливают прокрутку.

Вот App.js пример того, как можно использовать выше:

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; 

Из приведенного выше кода, что интересно отметить, что только при навигации по /about или /another-page СВИТОК к началу действий будет быть предварительно сформированным. Однако при переходе на / восстановление прокрутки не произойдет.

Все кодовое можно найти здесь: https://github.com/rizedr/react-router-scroll-top

+1

Только то, что я искал! Мне пришлось добавить scrollTo в componentDidMount ScrollToTopRoute, так как у меня есть мои маршруты, завернутые в компонент Switch (я также удалил if, если бы я хотел, чтобы он запускался на каждом монтировании) – tocallaghan

+0

В рендеринге вашего ScrollToTopRoute вы не нажимаете, t нужно указать render = {props => ()}. Просто использование {... rest} в маршруте будет работать. – Finickyflame

7

Документация для React v4 Router содержит code samples для восстановления прокрутки. Вот их первый пример кода, который служит в качестве веб-узле решения для «прокрутки к вершине», когда страница переходите к:

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) 

Затем сделать его в верхней части вашего приложения, но ниже маршрутизатора:

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

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

^ copied directly from the documentation

Очевидно, что это работает для большинства случаев, но есть больше о том, как иметь дело с вкладками интерфейсов и почему не было реализовано общее решение.

1

Я написал компонент более высокого порядка под названием withScrollToTop. Этот HOC принимает два флага:

  • onComponentWillMount - ли, чтобы перейти к началу навигации по (componentWillMount)
  • onComponentDidUpdate - ли, чтобы перейти к началу при обновлении (componentDidUpdate). Этот флаг необходим в случаях, когда компонент не размонтирован, но происходит событие навигации, например, от /users/1 до /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)); 
}; 

Чтобы использовать его:

import withScrollToTop from './withScrollToTop'; 

function MyComponent() { ... } 

export default withScrollToTop(MyComponent); 
Смежные вопросы