Как остановить / # / в браузере с помощью response-router?

103

Есть ли способ предотвратить /#/отображение в адресной строке браузера при использовании response-router? Это с ReactJS. т.е. щелчок по ссылкам для перехода к новому маршруту показывает localhost:3000/#/или localhost:3000/#/about. В зависимости от маршрута.

Гигантский лось
источник
1
Это связано с использованием HashHistoryiso BrowserHistory. См. Также этот вопрос SO, где я даю много справочной информации по этому вопросу.
Stijn de Witt

Ответы:

78

Для версий 1, 2 и 3 response-router правильный способ установить маршрут в схему сопоставления URL-адресов - передать реализацию истории в historyпараметр <Router>. Из документации по истории :

Короче говоря, история знает, как прослушивать адресную строку браузера на предмет изменений и анализировать URL-адрес в объект местоположения, который маршрутизатор может использовать для сопоставления маршрутов и отображения правильного набора компонентов.

Версии 2 и 3

В response-router 2 и 3 код конфигурации вашего маршрута будет выглядеть примерно так:

import { browserHistory } from 'react-router'
ReactDOM.render (( 
 <Router history={browserHistory} >
   ...
 </Router> 
), document.body);

Версия 1

В версии 1.x вместо этого вы будете использовать следующее:

import createBrowserHistory from 'history/lib/createBrowserHistory'
ReactDOM.render (( 
  <Router history={createBrowserHistory()} >
   ...
  </Router> 
), document.body);

Источник: Руководство по обновлению до версии 2.0.

Версия 4

Для грядущей версии 4 response-router синтаксис сильно изменился, и требуется использовать его BrowserRouterв качестве корневого тега маршрутизатора.

import BrowserRouter from 'react-router/BrowserRouter'
ReactDOM.render (( 
  <BrowserRouter>
   ...
 <BrowserRouter> 
), document.body);

Исходный код React Router Version 4 Docs

Адам Браун
источник
6
Обратите внимание, что historyэто отдельный пакет, который вам необходимо установить.
Ян Климо,
4
Они изменили browserHistoryв v2.x: import { browserHistory } from 'react-router' <Router history={browserHistory} />проверьте руководство по обновлению
реактивного
Спасибо @pistou, обновил ответ до версии 2.0!
Адам Браун
1
Ведь hashHistoryесть ли способ избавиться от этого параметра запроса в конце? http://localhost:8080/#/dashboard?_k=yqwtyu
Con Antonakos
2
@Matt Это работает, но требует поддержки на сервере. Это потому, что при обновлении вы попадаете на сервер с URL-адресом с путем.
Stijn de Witt
40
Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

Для текущей версии 0.11 и более поздних вам необходимо добавить Router.HistoryLocationв Router.run(). <Routes>устарели. См. Руководство по обновлению для реализации 0.12.x HistoryLocation.

pxwise
источник
1
это полностью испортило мое приложение. похоже, что их текущая реализация содержит ошибки?
ninjaneer 01
2
@Ninja, возможно, разместит новый вопрос с точными номерами версий для реагирующего и реагирующего маршрутизатора, ошибочного кода и полученных ошибок.
pxwise 06
@Chet Похоже, что документация по реактивному маршрутизатору перемешалась. Обновлена ​​ссылка на единственную ссылку на HistoryLocation, найденную в Руководстве по обновлению.
pxwise
21

Если вам не нужна поддержка IE8, вы можете использовать историю браузера, и response-router будет использовать window.pushStateвместо установки хеша.

Как именно это сделать, зависит от версии React Router, которую вы используете:

Софи Альперт
источник
Спасибо @ ben-alpert, теперь я понял.
Giant Elk
1
Я добавил, <Routes location="history">что все работает нормально, пока вы не обновите браузер, когда находитесь в пути, т.е. localhost:3000/aboutтогда я получаю ошибку 404. Это ожидается, я использую python -m SimpleHTTPServer 3000?
Giant Elk
5
Вы должны убедиться, что ваш сервер может обрабатывать URL-адрес состояния push. В этом случае это, вероятно, означает, что вам просто нужно убедиться, что все, что обслуживает ваше приложение, всегда отправляет каждый URL-адрес в один и тот же корень. Итак, это /aboutдействительно загружает вашу корневую страницу /. В противном случае ваш сервер пытается найти подходящий маршрут /aboutи ничего не находит (404). Я лично не использую python, но вы обычно находите либо ручной маршрут, /*либо /.*-> /работает - либо это может быть что-то, называемое html5ModeURL-адресами в настройках вашего сервера.
Майк Драйвер
3
IE9 также не поддерживает pushState - так что это действительно «если вам не нужно поддерживать IE9», верно? Хотел бы я ошибаться.
Cymen
1
Эта ссылка на github - это страница, которая сейчас не найдена.
k00k 07
9

На самом деле вы можете использовать .htaccess для этого. Браузеру обычно нужен разделитель строки запроса ?или #чтобы определить, где начинается строка запроса и заканчиваются пути к каталогам. Конечный результат, который мы хотим, www.mysite.com/dir таков: нам нужно выявить проблему до того, как веб-сервер начнет поиск каталога, который, по его мнению, мы запрашивали /dir. Итак, мы помещаем .htaccessфайл в корень проекта.

    # Setting up apache options
    AddDefaultCharset utf-8
    Options +FollowSymlinks -MultiViews -Indexes
    RewriteEngine on

    # Setting up apache options (Godaddy specific)
    #DirectoryIndex index.php
    #RewriteBase /


    # Defining the rewrite rules
    RewriteCond %{SCRIPT_FILENAME} !-d
    RewriteCond %{SCRIPT_FILENAME} !-f

    RewriteRule ^.*$ ./index.html

Затем вы получаете параметры запроса с помощью window.location.pathname

Затем вы можете избежать использования маршрутов реакции, если хотите, и просто манипулировать URL-адресом и историей браузера, если хотите. Надеюсь, это кому-то поможет ...

Гаррет Такоронте
источник
Что эквивалентно Jboss?
Рагхаван
5

Установите пакет истории

npm install history --save

Затем импортируйте createHistory и useBasename из истории

import { createHistory, useBasename } from 'history';
...
const history = useBasename(createHistory)({
  basename: '/root' 
});

Если URL вашего приложения - www.example.com/myApp, то / root должен быть / myApp.

передать историческую переменную маршрутизатору

render((
  <Router history={history}>
    ...
  </Router>
), document.getElementById('example'));

Теперь для всех ваших тегов ссылок добавьте «/» перед всеми путями.

<Link to="/somewhere">somewhere</Link>

Вдохновением для этого решения послужил пример React-Router, который, к сожалению, не был должным образом задокументирован в их API.

Mox
источник
для этого требуется сервер узла? Я пытаюсь добиться того же стиля URL, но только на стороне клиента. Является ли это возможным?
Sebastialonso
1
нет, вам не нужен сервер узла. На самом деле я работаю на бэкэнде django. Но вам наверняка понадобится узел для инструментов.
Mox
1
Хорошо, я пробовал этот подход. Когда я нажимаю F5, все, что я получаю, это «Не найдено». Может ли эта история справиться с этим?
Sebastialonso
если u не найден, сервер возвращает это. это означает, что шаблон URL-адреса не является частью реагирующего маршрутизатора.
Mox
1
Да, почитав еще немного, все стало понятно. Я закончил тем, что пошел с hashHistory без ключей.
Sebastialonso
3

Другой способ обработать то, что будет отображаться после хэша (так что, если вы не используете pushState!), - это создать свой CustomLocation и загрузить его при создании ReactRouter.

Например, если вы хотите иметь URL-адрес hashbang (например, с #!), Чтобы соответствовать спецификациям Google для сканирования, вы можете создать файл HashbangLocation.js, который в основном копирует исходный HashLocation, например:

'use strict';

var LocationActions = require('../../node_modules/react-router/lib/actions/LocationActions');
var History = require('../../node_modules/react-router/lib/History');

var _listeners = [];
var _isListening = false;
var _actionType;

function notifyChange(type) {
  if (type === LocationActions.PUSH) History.length += 1;

  var change = {
    path: HashbangLocation.getCurrentPath(),
    type: type
  };

  _listeners.forEach(function (listener) {
    listener.call(HashbangLocation, change);
  });
}

function slashToHashbang(path) {
  return "!" + path.replace(/^\//, '');
}

function ensureSlash() {

  var path = HashbangLocation.getCurrentPath();
  if (path.charAt(0) === '/') {
    return true;
  }HashbangLocation.replace('/' + path);

  return false;
}

function onHashChange() {
  if (ensureSlash()) {
    // If we don't have an _actionType then all we know is the hash
    // changed. It was probably caused by the user clicking the Back
    // button, but may have also been the Forward button or manual
    // manipulation. So just guess 'pop'.
    var curActionType = _actionType;
    _actionType = null;
    notifyChange(curActionType || LocationActions.POP);
  }
}

/**
 * A Location that uses `window.location.hash`.
 */
var HashbangLocation = {

  addChangeListener: function addChangeListener(listener) {
    _listeners.push(listener);

    // Do this BEFORE listening for hashchange.
    ensureSlash();

    if (!_isListening) {
      if (window.addEventListener) {
        window.addEventListener('hashchange', onHashChange, false);
      } else {
        window.attachEvent('onhashchange', onHashChange);
      }

      _isListening = true;
    }
  },

  removeChangeListener: function removeChangeListener(listener) {
    _listeners = _listeners.filter(function (l) {
      return l !== listener;
    });

    if (_listeners.length === 0) {
      if (window.removeEventListener) {
        window.removeEventListener('hashchange', onHashChange, false);
      } else {
        window.removeEvent('onhashchange', onHashChange);
      }

      _isListening = false;
    }
  },

  push: function push(path) {
    _actionType = LocationActions.PUSH;
    window.location.hash = slashToHashbang(path);
  },

  replace: function replace(path) {
    _actionType = LocationActions.REPLACE;
    window.location.replace(window.location.pathname + window.location.search + '#' + slashToHashbang(path));
  },

  pop: function pop() {
    _actionType = LocationActions.POP;
    History.back();
  },

  getCurrentPath: function getCurrentPath() {
    return decodeURI(
    // We can't use window.location.hash here because it's not
    // consistent across browsers - Firefox will pre-decode it!
    "/" + (window.location.href.split('#!')[1] || ''));
  },

  toString: function toString() {
    return '<HashbangLocation>';
  }

};

module.exports = HashbangLocation;

Обратите внимание на функцию slashToHashbang .

Тогда вы должны сделать

ReactRouter.create({location: HashbangLocation})

И это все :-)

Джонатан Бэнон
источник