【问题标题】:How to stop /#/ in browser with react-router?如何使用 react-router 在浏览器中停止 /#/?
【发布时间】:2014-09-25 01:07:31
【问题描述】:

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

【问题讨论】:

  • 这是由于使用HashHistory i.s.o. BrowserHistory。另请参阅this SO question,我在其中提供了有关此主题的大量背景信息。

标签: reactjs react-router


【解决方案1】:

对于 react-router 的版本 1、2 和 3,设置路由到 URL 映射方案的正确方法是将历史实现传递给 <Router>history 参数。来自histories documentation

简而言之,历史知道如何监听浏览器地址栏的变化,并将 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);

来源:Version 2.0 Upgrade Guide

版本 4

对于即将发布的第四版 react-router,语法发生了很大变化,需要使用BrowserRouter 作为路由器根标签。

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

来源React Router Version 4 Docs

【讨论】:

  • 请注意,history 是您需要安装的 stand-alone package
  • 他们在 v2.x 中更改了browserHistoryimport { browserHistory } from 'react-router' &lt;Router history={browserHistory} /&gt; 检查react-router upgrade guide
  • 感谢@pistou,我已将答案更新到 2.0 版!
  • 对于hashHistory,最后有没有办法摆脱这个查询参数? http://localhost:8080/#/dashboard?_k=yqwtyu
  • @Matt 确实有效,但需要服务器支持。这是因为当您刷新时,您会使用带有路径的 URL 访问服务器。
【解决方案2】:
Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

对于当前版本 0.11 及更高版本,您需要将Router.HistoryLocation 添加到Router.run()&lt;Routes&gt; 现在已弃用。 See the Upgrade Guide 用于 0.12.x HistoryLocation 实现。

【讨论】:

  • 这完全毁了我的应用程序。看起来他们当前的实现有问题?
  • @Ninja 可能会发布一个新问题,其中包含 react 和 react-router 的确切版本号、失败的代码和收到的错误。
  • @Chet 看起来 react-router 文档已经改组了。更新了指向升级指南中的 HistoryLocation 唯一参考的链接。
【解决方案3】:

【讨论】:

  • 谢谢@ben-alpert,我现在明白了。
  • 我添加了 &lt;Routes location="history"&gt; 一切正常,直到您在路线上刷新浏览器,即 localhost:3000/about 然后我收到 404 错误。这是预期的吗,我使用的是python -m SimpleHTTPServer 3000
  • 您需要确保您的服务器端可以处理推送状态 url。在这种情况下,这可能意味着您只需要确保为您的应用程序提供服务的任何东西总是将它获得的每个 url 发送到同一个根目录。这样/about 实际上会加载您的根页面/。否则,您的服务器会尝试寻找与/about 匹配的路由,但什么也找不到(404)。我个人不使用 python,但您通常会在您的服务器设置中找到 /*/.* 的手动路由 -> / 有效 - 或者它可能是名为 html5Mode 的 URL。
  • IE9 也不支持 pushState - 所以这真的是“如果你不需要支持 IE9”对吗?我希望我错了。
  • 那个 github 链接是一个现在找不到的页面。
【解决方案4】:

您实际上可以使用 .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' 
});

如果您的应用网址是 www.example.com/myApp,那么 /root 应该是 /myApp。

将历史变量传递给路由器

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

现在,对于所有链接标签,在所有路径前附加一个“/”。

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

解决方案的灵感来自React-Router Example 不幸的是,他们的 API 中没有正确记录。

【讨论】:

  • 这需要节点服务器吗?我正在尝试实现相同的 URL 样式,但只能通过客户端。有可能吗?
  • 不,您不需要节点服务器。事实上,我在 django 后端运行。但是您可能需要 node 来获取工具。
  • 好的,我试过这种方法。当我按 F5 时,我得到的只是“未找到”。这段历史有可能解决这个问题吗?
  • 如果你没有被找到,那是由服务器返回的。这意味着 url 模式不是反应路由器的一部分。
  • 是的,多读了一会儿,一切都清楚了。我最终选择了没有键的 hashHistory。
【解决方案6】:

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

例如,如果你想让hashbang url(所以用#!)来符合谷歌的抓取规范,你可以创建一个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})

就是这样:-)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-03
    • 2017-10-16
    • 1970-01-01
    • 1970-01-01
    • 2017-12-29
    • 2015-08-17
    • 1970-01-01
    相关资源
    最近更新 更多