Làm cách nào để dừng / # / trong trình duyệt với bộ định tuyến phản ứng?


103

Có cách nào để ngăn không /#/cho hiển thị trên thanh địa chỉ của trình duyệt khi sử dụng bộ định tuyến phản ứng không? Đó là với ReactJS. tức là Nhấp vào liên kết để đi đến một tuyến đường mới cho thấy localhost:3000/#/hoặc localhost:3000/#/about. Tùy thuộc vào tuyến đường.


1
Đó là do sử dụng HashHistoryiso BrowserHistory. Xem thêm câu hỏi SO này , nơi tôi cung cấp rất nhiều thông tin cơ bản về chủ đề này.
Stijn de Witt,

Câu trả lời:


78

Đối với các phiên bản 1, 2 và 3 của react-router, cách chính xác để đặt đường dẫn đến lược đồ ánh xạ URL là chuyển một triển khai lịch sử vào historytham số của <Router>. Từ tài liệu lịch sử :

Tóm lại, lịch sử biết cách lắng nghe thanh địa chỉ của trình duyệt để biết các thay đổi và phân tích cú pháp URL thành một đối tượng vị trí mà bộ định tuyến có thể sử dụng để khớp các tuyến và hiển thị đúng tập hợp các thành phần.

Phiên bản 2 và 3

Trong react-router 2 và 3, mã cấu hình tuyến đường của bạn sẽ giống như sau:

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

Phiên bản 1

Trong phiên bản 1.x, thay vào đó bạn sẽ sử dụng những thứ sau:

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

Nguồn: Hướng dẫn nâng cấp phiên bản 2.0

Phiên bản 4

Đối với phiên bản 4 sắp tới của react-router, cú pháp đã thay đổi rất nhiều và nó bắt buộc phải sử dụng BrowserRouterlàm thẻ gốc của router.

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

Nguồn React Router Version 4 Docs


6
Lưu ý rằng đó historylà một gói độc lập mà bạn cần cài đặt.
Jan Klimo

4
Họ đã thay đổi browserHistorytrong v2.x: import { browserHistory } from 'react-router' <Router history={browserHistory} />Kiểm tra hướng dẫn nâng cấp bộ định tuyến phản ứng
pistou

Cảm ơn @pistou, tôi đã cập nhật câu trả lời lên phiên bản 2.0!
Adam Brown

1
Đối với hashHistory, có cách nào để loại bỏ tham số truy vấn này ở cuối không? http://localhost:8080/#/dashboard?_k=yqwtyu
Con Antonakos

2
@Matt Nó hoạt động, nhưng yêu cầu hỗ trợ trên máy chủ. Đó là bởi vì khi bạn làm mới, bạn nhấn vào máy chủ với một URL có đường dẫn.
Stijn de Witt,

40
Router.run(routes, Router.HistoryLocation, function (Handler) {
  React.render(<Handler/>, document.body);
});

Đối với phiên bản hiện tại 0.11 trở đi, bạn cần thêm Router.HistoryLocationvào Router.run().<Routes>hiện không được dùng nữa. Xem Hướng dẫn nâng cấp để triển khai HistoryLocation 0.12.x.


1
điều này hoàn toàn làm hỏng ứng dụng của tôi. có vẻ như việc triển khai hiện tại của họ có lỗi?
ninjaneer

2
@Ninja có lẽ đăng một câu hỏi mới với số phiên bản chính xác cho bộ định tuyến phản ứng và phản ứng, mã lỗi và nhận được lỗi.
pxwise

@Chet Có vẻ như tài liệu của bộ định tuyến phản ứng đã bị xáo trộn. Liên kết cập nhật đến tài liệu tham khảo duy nhất cho HistoryLocation được tìm thấy trong Hướng dẫn nâng cấp.
pxwise

21

Nếu bạn không cần hỗ trợ IE8, bạn có thể sử dụng Lịch sử trình duyệt và bộ định tuyến phản ứng sẽ sử dụng window.pushStatethay vì đặt băm.

Cách thực hiện chính xác tùy thuộc vào phiên bản React Router mà bạn đang sử dụng:


Cảm ơn @ ben-alpert, tôi nhận được ngay.
Giant Elk

1
Tôi đã thêm <Routes location="history">tất cả đều hoạt động tốt, cho đến khi bạn làm mới trình duyệt khi đang trên đường tức là localhost:3000/aboutsau đó tôi gặp lỗi 404. Đó là mong đợi, tôi đang sử dụng python -m SimpleHTTPServer 3000?
Giant Elk

5
Bạn cần đảm bảo rằng phía máy chủ của mình có thể xử lý url trạng thái đẩy. Trong trường hợp này, điều đó có nghĩa là bạn chỉ cần đảm bảo rằng bất kỳ thứ gì đang phục vụ ứng dụng của bạn luôn gửi mọi url mà nó đến cùng một gốc. Vì vậy, điều đó /aboutthực sự tải trang gốc của bạn /. Nếu không, máy chủ của bạn đang cố gắng tìm kiếm một tuyến đường phù hợp /aboutvà không tìm thấy gì (404). Cá nhân tôi không sử dụng python nhưng bạn thường tìm thấy một tuyến thủ công cho /*hoặc /.*-> /hoạt động - hoặc nó có thể là một cái gì đó được gọi là html5Modeurl trong cài đặt máy chủ của bạn.
Mike Driver

3
IE9 cũng không hỗ trợ pushState - vì vậy đó thực sự là "Nếu bạn không cần hỗ trợ IE9" phải không? Tôi ước tôi đã sai.
Cymen

1
Liên kết github đó là một trang không được tìm thấy bây giờ.
k00k

9

Bạn thực sự có thể sử dụng .htaccess để thực hiện điều này. Trình duyệt thường cần dấu phân cách chuỗi truy vấn ?hoặc #để xác định nơi bắt đầu chuỗi truy vấn và kết thúc đường dẫn thư mục. Kết quả cuối cùng chúng tôi muốn là www.mysite.com/dir Vì vậy, chúng tôi cần nắm bắt vấn đề trước khi máy chủ web tìm kiếm thư mục mà nó cho rằng chúng tôi đã yêu cầu /dir. Vì vậy, chúng tôi đặt một .htaccesstệp trong thư mục gốc của dự án.

    # 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

Sau đó, bạn nhận được các tham số truy vấn với window.location.pathname

Sau đó, bạn có thể tránh sử dụng các tuyến phản ứng nếu bạn muốn và chỉ cần thao tác url và lịch sử trình duyệt nếu bạn muốn. Hy vọng điều này sẽ giúp ai đó ...


Tương đương với Jboss là gì?
Raghavan

5

Cài đặt gói lịch sử

npm install history --save

Tiếp theo nhập createHistory và useBasename từ lịch sử

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

nếu url ứng dụng của bạn là www.example.com/myApp thì / root phải là / myApp.

chuyển biến lịch sử cho Bộ định tuyến

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

Bây giờ, đối với tất cả các thẻ Liên kết của bạn, hãy thêm dấu "/" vào trước tất cả các đường dẫn.

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

Nguồn cảm hứng của giải pháp đến từ Ví dụ về React-Router , nhưng thật không may, nó không được ghi lại đúng cách trong API của họ.


điều này có yêu cầu một máy chủ nút không? Tôi đang cố gắng đạt được cùng một kiểu URL nhưng chỉ thông qua phía khách hàng. Nó có khả thi không?
Sebastialonso

1
nope, bạn không cần một máy chủ nút. Trên thực tế, tôi đang chạy trên chương trình phụ trợ django. Nhưng bạn có thể cần nút cho các công cụ.
Mox

1
Ok, tôi đã thử cách tiếp cận này. Khi tôi nhấn F5, tất cả những gì tôi nhận được là "Không tìm thấy". Có thể cho lịch sử này để đối phó với điều đó?
Sebastialonso

nếu u không được tìm thấy, nó sẽ được máy chủ trả về. điều này có nghĩa là mẫu url không phải là một phần của bộ định tuyến phản ứng.
Mox

1
Vâng, sau khi đọc thêm một chút, mọi thứ đã trở nên rõ ràng. Tôi đã kết thúc nó với hashHistory mà không có chìa khóa.
Sebastialonso

3

Một cách khác để xử lý những gì sẽ hiển thị sau khi băm (vì vậy nếu bạn không sử dụng pushState!) Là tạo CustomLocation của bạn và tải nó khi tạo ReactRouter.

Đối với ví dụ điển hình, nếu bạn muốn có url hashbang (tương tự với #!) Để tuân thủ các thông số kỹ thuật của google để thu thập thông tin, bạn có thể tạo tệp HashbangLocation.js chủ yếu sao chép HashLocation ban đầu như:

'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;

Lưu ý đến hàm SlashToHashbang .

Sau đó, bạn biện minh phải làm

ReactRouter.create({location: HashbangLocation})

Và thế là xong :-)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.