如何使用react-router在浏览器中停止/#/?


103

有什么方法可以防止/#/使用react-router时在浏览器的地址栏中显示?那就是ReactJS。即,单击链接以转到新路线将显示localhost:3000/#/localhost:3000/#/about。取决于路线。


1
这是因为使用了HashHistoryiso BrowserHistory。另请参见此问题,在此我将提供有关此主题的很多背景信息。
Stijn de Witt

Answers:


78

对于react-router的版本1、2和3,将路由设置为URL映射方案的正确方法是将历史记录实现传递给history参数<Router>。从历史记录文档中

简而言之,历史记录知道如何侦听浏览器的地址栏以进行更改,并将URL解析为一个位置对象,路由器可以使用该对象来匹配路由并呈现正确的组件集。

版本2和3

在react-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

对于即将发布的react-router版本4,语法已进行了很大的更改,并且要求将其BrowserRouter用作路由器根标签。

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

React Router版本4文档


6
请注意,这history是您需要安装的独立软件包
Jan Klimo 2015年

4
他们更改了browserHistoryv2.x中的版本:import { browserHistory } from 'react-router' <Router history={browserHistory} />检查react-router升级指南
pistou

感谢@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.HistoryLocationRouter.run()<Routes>现在已弃用。有关 0.12.x HistoryLocation的实现,请参阅《升级指南》


1
这完全毁了我的应用程序。看起来他们当前的实现存在错误?
ninjaneer 2015年

2
@Ninja可能会发布一个新问题,其中包含关于react和react-router,失败的代码和收到的错误的确切版本号。
pxwise 2015年

@Chet似乎react-router文档已经改组。已更新链接,使其指向《升级指南》中有关HistoryLocation的唯一参考。
pxwise

21

如果不需要支持IE8,则可以使用“浏览器历史记录”,然后使用react-router window.pushState代替设置哈希。

具体如何执行取决于您使用的React Router版本:


谢谢@ ben-alpert,我现在明白了。
巨麋鹿

1
我添加<Routes location="history">了所有的东西,一切正常,直到您在路上刷新浏览器为止,即localhost:3000/about我收到404错误。这是预期的,我正在使用python -m SimpleHTTPServer 3000吗?
巨麋鹿

5
您需要确保您的服务器端可以处理推送状态网址。在这种情况下,这可能意味着您只需要确保为您的应用提供服务的内容始终将其获取的每个URL发送到同一根目录即可。这样/about实际上会加载您的根页面/。否则,您的服务器将尝试寻找匹配/about且什么也找不到的路由(404)。我个人不使用python,但是您通常会找到用于/*/.*-> /有效的手动路线-否则它可能是html5Mode服务器设置中的url。
Mike Driver

3
IE9也不支持pushState,所以实际上是“如果您不需要支持IE9”对吗?我希望我错了。
Cymen

1
那个github链接是现在找不到的页面。
k00k 2016年

9

您实际上可以使用.htaccess来完成此操作。浏览器通常需要查询字符串定界符?#确定查询字符串在何处开始以及目录路径在何处结束。我们想要的最终结果是www.mysite.com/dir 因此,我们需要在Web服务器搜索它认为我们的目录之前捕获问题/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获取查询参数

然后,您可以根据需要避免使用react路由,并且也可以仅操纵url和浏览器历史记录。希望这可以帮助某人...


Jboss等于什么?
拉格万

5

安装历史记录包

npm install history --save

接下来从历史记录中导入createHistory和useBasename

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

如果您的应用程序网址是www.example.com/myApp,则/ root应该是/ myApp。

将历史记录变量传递给路由器

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

现在,对于所有Link标记,在所有路径之前添加一个“ /”。

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

该解决方案的灵感来自于React-Router Example, 不幸的是,其API中并未对其进行正确记录。


这需要一个节点服务器吗?我正在尝试通过客户端实现相同的URL样式。可能吗?
Sebastialonso

1
不,您不需要节点服务器。实际上,我在Django后端上运行。但是您可能需要工具节点。
Mox

1
好的,我尝试了这种方法。当我按F5时,我得到的只是“未找到”。这个历史有可能解决吗?
Sebastialonso

如果找不到您,则由服务器返回。这意味着URL模式不是反应路由器的一部分。
Mox

1
是的,阅读更多之后,一切都变得清晰了。我最终使用了没有密钥的hashHistory。
Sebastialonso

3

处理哈希后显示的内容的另一种方法(因此,如果您不使用pushState!)是创建您的CustomLocation并在ReactRouter创建时将其加载。

例如,如果您想让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})

就是这样:-)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.