Подтвердить что ты не робот

Использовать якоря с реактивным маршрутизатором

Как я могу использовать ретранслятор-ретранслятор и иметь ссылку для перехода к определенному месту на определенной странице? (например, /home-page#section-three)

Подробнее

Я использую react-router в приложении React.

У меня есть навигационная панель сайта, которая должна ссылаться на определенные части страницы, например /home-page#section-three.

Итак, даже если вы говорите /blog, нажатие этой ссылки по-прежнему будет загружать главную страницу, при этом прокручивается раздел-три. Именно так будет работать стандартный <a href="/home-page#section-three>.

Примечание. Создатели ответного маршрутизатора не дали явного ответа. Они говорят, что это происходит, и в то же время используют ответы других людей. Я сделаю все возможное, чтобы этот вопрос обновился с прогрессом и возможными решениями, пока не появится доминирующий.

Исследование


Как использовать обычные якорные ссылки с реактивным маршрутизатором

Этот вопрос с 2015 года (так 10 лет назад в ответное время). В наиболее употребительном ответе используется HistoryLocation вместо HashLocation. В основном это означает сохранение местоположения в истории окна, а не в хэш-фрагменте.

Плохая новость... даже с использованием HistoryLocation (что большинство учебных пособий и документов говорят делать в 2016 году), теги привязки все еще не работают.


https://github.com/ReactTraining/react-router/issues/394

Поток на ReactTraining о том, как использовать привязные ссылки с реактивным маршрутизатором. Это не подтвержденный ответ. Будьте осторожны, так как большинство предлагаемых ответов устарели (например, используя "хэш" в <Link>)


4b9b3361

Ответ 1

Вот одно из решений, которое я нашел (октябрь 2016 года). Он совместим с кросс-браузером (протестирован, например, ff, chrome, мобильное сафари, сафари).

Вы можете предоставить свойство onUpdate для вашего маршрутизатора. Это называется в любое время обновления маршрута. Это решение использует свойство onUpdate для проверки наличия элемента DOM, который соответствует хешу, и затем прокручивается к нему после завершения перехода по маршруту.

Вы должны использовать browserHistory, а не hashHistory.

Ответа на этот вопрос "Rafrax" в этом .

Добавьте этот код в том месте, где вы определяете <Router>:

import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';

const routes = (
  // your routes
);

function hashLinkScroll() {
  const { hash } = window.location;
  if (hash !== '') {
    // Push onto callback queue so it runs after the DOM is updated,
    // this is required when navigating from a different page so that
    // the element is rendered on the page before trying to getElementById.
    setTimeout(() => {
      const id = hash.replace('#', '');
      const element = document.getElementById(id);
      if (element) element.scrollIntoView();
    }, 0);
  }
}

render(
  <Router
    history={browserHistory}
    routes={routes}
    onUpdate={hashLinkScroll}
  />,
  document.getElementById('root')
)

Если вы чувствуете себя ленивым и не хотите копировать этот код, вы можете использовать Anchorate, который просто определяет эту функцию для вас. https://github.com/adjohnson916/anchorate

Ответ 2

У меня работал React Router Hash Link. Простота установки и реализации:

$ npm install --save react-router-hash-link

В вашем component.js импортируйте его как Link:

import { HashLink as Link } from 'react-router-hash-link';

И вместо использования якоря <a>, используйте <Link>:

<Link to="home-page#section-three">Section three</Link>

ПРИМЕЧАНИЕ: я использовал HashRouter вместо Router:

Ответ 3

Просто избегайте использования реактивного маршрутизатора для локальной прокрутки:

document.getElementById('myElementSomewhere').scrollIntoView() 

Ответ 4

Проблема с fooobar.com/questions/211809/... иногда элемент с идентификатором по-прежнему отображается или загружается, если этот раздел зависит от какого-либо действия async. Следующая функция попытается найти элемент по id и перейти к нему и повторить каждые 100 мс, пока не достигнет 50 попыток:

scrollToLocation = () => {
  const { hash } = window.location;
  if (hash !== '') {
    let retries = 0;
    const id = hash.replace('#', '');
    const scroll = () => {
      retries += 0;
      if (retries > 50) return;
      const element = document.getElementById(id);
      if (element) {
        setTimeout(() => element.scrollIntoView(), 0);
      } else {
        setTimeout(scroll, 100);
      }
    };
    scroll();
  }
}

Ответ 5

Альтернатива: реакция-scrollchor https://www.npmjs.com/package/react-scrollchor

response-scrollchor: компонент React для прокрутки ссылок #hash с плавной анимацией. Scrollchor - это сочетание прокрутки и привязки

ПРИМЕЧАНИЕ. Он не использует реактивный маршрутизатор

Ответ 6

Здесь простое решение, которое не требует подписок или сторонних пакетов. Должен работать с [email protected] и выше и react-router-dom.

Рабочий пример: https://fglet.codesandbox.io/

Источник (к сожалению, в настоящее время не работает в редакторе):

Edit Simple React Anchor


Пример ScrollHandler Hook

import { useEffect } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";

const ScrollHandler = ({ location, children }) => {
  useEffect(
    () => {
      const element = document.getElementById(location.hash.replace("#", ""));

      setTimeout(() => {
        window.scrollTo({
          behavior: element ? "smooth" : "auto",
          top: element ? element.offsetTop : 0
        });
      }, 100);
    }, [location]);
  );

  return children;
};

ScrollHandler.propTypes = {
  children: PropTypes.node.isRequired,
  location: PropTypes.shape({
    pathname: PropTypes.string,
    search: PropTypes.string,
    hash: PropTypes.string,
    state: PropTypes.any,
    key: PropTypes.string
  }).isRequired
};

export default withRouter(ScrollHandler);

Пример класса ScrollHandler

import { PureComponent } from "react";
import PropTypes from "prop-types";
import { withRouter } from "react-router-dom";

class ScrollHandler extends PureComponent {
  componentDidMount = () => this.handleScroll();

  componentDidUpdate = prevProps => {
    const { location: { pathname, hash } } = this.props;
    if (
      pathname !== prevProps.location.pathname ||
      hash !== prevProps.location.hash
    ) {
      this.handleScroll();
    }
  };

  handleScroll = () => {
    const { location: { hash } } = this.props;
    const element = document.getElementById(hash.replace("#", ""));

    setTimeout(() => {
      window.scrollTo({
        behavior: element ? "smooth" : "auto",
        top: element ? element.offsetTop : 0
      });
    }, 100);
  };

  render = () => this.props.children;
};

ScrollHandler.propTypes = {
  children: PropTypes.node.isRequired,
  location: PropTypes.shape({
    hash: PropTypes.string,
    key: PropTypes.string,
    pathname: PropTypes.string,
    search: PropTypes.string,
    state: PropTypes.any
  })
};

export default withRouter(ScrollHandler);

Ответ 7

Я адаптировал решение Don P (см. Выше) к react-router 4 (январь 2019 г.), поскольку на <Router> больше нет поддержки onUpdate.

import React from 'react';
import * as ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { createBrowserHistory } from 'history';

const browserHistory = createBrowserHistory();

browserHistory.listen(location => {
    const { hash } = location;
    if (hash !== '') {
        // Push onto callback queue so it runs after the DOM is updated,
        // this is required when navigating from a different page so that
        // the element is rendered on the page before trying to getElementById.
        setTimeout(
            () => {
                const id = hash.replace('#', '');
                const element = document.getElementById(id);
                if (element) {
                    element.scrollIntoView();
                }
            },
            0
        );
    }
});

ReactDOM.render(
  <Router history={browserHistory}>
      // insert your routes here...
  />,
  document.getElementById('root')
)