Thay đổi URL trong trình duyệt mà không tải trang mới bằng JavaScript


297

Làm cách nào để tôi có một hành động JavaScript có thể có một số hiệu ứng trên trang hiện tại nhưng cũng sẽ thay đổi URL trong trình duyệt để nếu người dùng nhấn tải lại hoặc đánh dấu, thì URL mới được sử dụng?

Sẽ rất tuyệt nếu nút quay lại tải lại URL gốc.

Tôi đang cố gắng ghi lại trạng thái JavaScript trong URL.


1
Điều này sẽ rất tốt Tất nhiên nó sẽ bị giới hạn trong các sửa đổi cùng tên miền. Nhưng một số điều khiển phía máy khách (và không chỉ băm) là một bước hợp lý bây giờ khi tải lại trang là một loại "phương sách cuối cùng" cho nhiều ứng dụng.
harpo

1
Cách sử dụng tốt "sắp xếp" của pushState:for(i=1;i<50;i++){var txt="..................................................";txt=txt.slice(0,i)+"HTML5"+txt.slice(i,txt.length);history.pushState({}, "html5", txt);}
Derek 會

ví dụ về hiệu ứng này trong hành động: dujour.com
Ben

2
Ví dụ về hiệu ứng này: facebook.com (Khi mở hình ảnh trong hộp đèn)

Đây là một câu hỏi hay. tuy nhiên, một tình huống đáng buồn ở đây là nếu câu hỏi thiis đã được hỏi theo cách này ngày hôm nay, thì nó sẽ bị hạ cấp và nhảy lên bởi "đây không phải là trang web mà bạn khiến mọi người viết tất cả mã cho bạn".
sương

Câu trả lời:


118

Với HTML 5, sử dụng history.pushStatechức năng . Ví dụ:

<script type="text/javascript">
var stateObj = { foo: "bar" };
function change_my_url()
{
   history.pushState(stateObj, "page 2", "bar.html");
}
var link = document.getElementById('click');
link.addEventListener('click', change_my_url, false);
</script>

và a href:

<a href="#" id='click'>Click to change url to bar.html</a>

Nếu bạn muốn thay đổi URL mà không cần thêm mục vào danh sách nút quay lại, hãy sử dụng history.replaceStatethay thế.


Bạn nói đúng, lần trước tôi đã thử nghiệm với Chrome. Tôi mới thử dùng Firefox 3.6 trên Ubuntu, nó không hoạt động. Tôi đoán chúng ta sẽ phải đợi cho đến khi HTML5 được hỗ trợ đầy đủ trong FF
clu3

15
Mã mẫu được cắt và dán từ developer.mozilla.org/en/DOM/Manipulation_the_browser_history . Mà thực sự phiền giải thích foo và bar có nghĩa là gì trong trường hợp này.
mikemaccana

2
Foo và bar không có nghĩa gì cả, đó là một đối tượng trạng thái được xác định tùy ý mà bạn có thể quay lại sau.
Paul Dixon

3
@Paul: vâng, bài viết trên cung cấp thông tin đó.
mikemaccana

2
NHƯ khi đăng bình luận này, nó hoạt động trên firefox chrome và safari. Không may mắn với safari di động trên ipad hoặc iphone mặc dù :(
Sid

187

Nếu bạn muốn nó làm việc trong các trình duyệt không hỗ trợ history.pushStatehistory.popStatebài viết nào, cách "cũ" là để thiết lập các định danh đoạn, trong đó sẽ không gây ra một tải lại trang.

Ý tưởng cơ bản là đặt thuộc window.location.hashtính thành giá trị chứa bất kỳ thông tin trạng thái nào bạn cần, sau đó sử dụng sự kiện window.onhashchange hoặc cho các trình duyệt cũ không hỗ trợ onhashchange(IE <8, Firefox <3.6), kiểm tra định kỳ xem nếu băm đã thay đổi ( setIntervalví dụ sử dụng ) và cập nhật trang. Bạn cũng sẽ cần kiểm tra giá trị băm khi tải trang để thiết lập nội dung ban đầu.

Nếu bạn đang sử dụng jQuery, có một plugin hashchange sẽ sử dụng bất kỳ phương thức nào mà trình duyệt hỗ trợ. Tôi chắc chắn cũng có plugin cho các thư viện khác.

Một điều cần cẩn thận là va chạm với id trên trang, bởi vì trình duyệt sẽ cuộn đến bất kỳ yếu tố nào có id phù hợp.


2
Đừng tìm kiếm công cụ bỏ qua các liên kết nội bộ (băm)? Trong kịch bản của tôi, tôi muốn các con nhện cũng chọn các liên kết này.
vẽ Noakes

3
@Drew, theo như tôi biết, không có cách nào để các công cụ tìm kiếm coi một phần của trang là một kết quả riêng biệt.
Matthew Crumley

8
Hiện tại có một đề xuất để làm cho các công cụ tìm kiếm thấy băm: googlewebmastercentral.blogspot.com/2009/10/ trên
LKM

5
Thay vì sử dụng setIntervalđể kiểm tra người document.location.hashta có thể sử dụng hashchangesự kiện này, vì nó được chấp nhận nhiều hơn. Kiểm tra ở đây để biết những gì trình duyệt hỗ trợ từng tiêu chuẩn . Cách tiếp cận hiện tại của tôi là sử dụng push / popState trên các trình duyệt hỗ trợ nó. Mặt khác, tôi đặt hàm băm và chỉ xem các hashchangetrình duyệt hỗ trợ. Điều này khiến IE <= 7 không có hỗ trợ lịch sử, nhưng với permalink hữu ích. Nhưng ai quan tâm đến IE <= 7 lịch sử?
Irae Carvalho

2
@gabeDel Có, mặc dù tôi không nghĩ rằng Analytics ghi lại hàm băm, vì vậy nó sẽ có cùng một URL. Cách tốt hơn là gọi thủ công bằng _trackPageviewURL "thực" của trang mới.
Matthew Crumley

37

window.location.href chứa URL hiện tại. Bạn có thể đọc từ nó, bạn có thể thêm vào nó và bạn có thể thay thế nó, điều này có thể gây ra tải lại trang.

Nếu, có vẻ như, bạn muốn ghi lại trạng thái javascript trong URL để có thể đánh dấu trang mà không cần tải lại trang, nối nó vào URL hiện tại sau khi # và có một đoạn javascript được kích hoạt bởi sự kiện onload phân tích hiện tại URL để xem nếu nó chứa trạng thái lưu.

Nếu bạn sử dụng một? thay vì #, bạn sẽ buộc tải lại trang, nhưng vì bạn sẽ phân tích trạng thái đã lưu khi tải nên điều này thực sự không phải là vấn đề; và điều này sẽ làm cho các nút chuyển tiếp và quay lại hoạt động chính xác.


2
ghi lại trạng thái javascript trong URL chính xác là những gì tôi đang cố gắng thực hiện
Steven Noble

21

Tôi chắc chắn sẽ nghi ngờ điều này là không thể, bởi vì nó sẽ là một vấn đề bảo mật đáng kinh ngạc nếu nó xảy ra. Ví dụ: tôi có thể tạo một trang trông giống như trang đăng nhập ngân hàng và làm cho URL trong thanh địa chỉ trông giống như ngân hàng thật !

Có lẽ nếu bạn giải thích lý do tại sao bạn muốn làm điều này, mọi người có thể đề xuất các phương pháp thay thế ...

[Chỉnh sửa vào năm 2011: Kể từ khi tôi viết câu trả lời này vào năm 2008, nhiều thông tin đã được đưa ra ánh sáng liên quan đến một kỹ thuật HTML5 cho phép sửa đổi URL miễn là nó có cùng nguồn gốc]


6
Không có quá nhiều vấn đề nếu các thay đổi không tải lại bị giới hạn ở đường dẫn, chuỗi truy vấn và phân đoạn, tức là không phải là cơ quan có thẩm quyền (tên miền và như vậy).
Ollie Saunders

2
youtube.com/user/SilkyDKwan#p/u/2/gTfqaGYVfMg là một ví dụ có thể, hãy thử chuyển đổi video :)
Spidfire

Bạn chỉ có thể thay đổi vị trí.hash (mọi thứ sau dấu #), như Matthew Chumley ghi chú trong câu trả lời được chấp nhận.
Paul Dixon

2
Bạn có sử dụng Facebook không? Facebook thay đổi URL mà không cần tải lại, sử dụng history.pushState().
Derek 朕 會 功夫

Paul Dixon, bạn nên chú ý hộp thư đến facebook, khi bạn nhấp vào tên ở bên trái, chỉ cần URL được thay đổi và trò chuyện mới được tải trong hộp trò chuyện, trang không được làm mới. Ngoài ra còn có rất nhiều trang web trên WebGL họ cũng làm như vậy
Dheeraj Thedijje

8

Cài đặt bảo mật trình duyệt ngăn mọi người sửa đổi url được hiển thị trực tiếp. Bạn có thể tưởng tượng các lỗ hổng lừa đảo sẽ gây ra.

Chỉ có cách đáng tin cậy để thay đổi url mà không thay đổi trang là sử dụng liên kết nội bộ hoặc hàm băm. ví dụ: http://site.com/page.html trở thành http://site.com/page.html#item1 . Kỹ thuật này thường được sử dụng trong Hijax (AJAX + bảo tồn lịch sử).

Khi thực hiện điều này, tôi thường chỉ sử dụng các liên kết cho các hành động với hàm băm là href, sau đó thêm các sự kiện nhấp chuột với jquery sử dụng hàm băm được yêu cầu để xác định và ủy thác hành động.

Tôi hy vọng điều đó đặt bạn trên con đường đúng.


Xin lỗi nhưng câu trả lời của bạn không đúng. Có, bạn có thể thay đổi URL.
Derek 朕 會 功夫

1
Có, bạn có thể sử dụng api lịch sử html5 nhưng nó không phải là trình duyệt chéo, mặc dù bạn có thể sử dụng một poly-fill sẽ dự phòng để băm các url.
Jethro Larson

8

jQuery có một plugin tuyệt vời để thay đổi URL của trình duyệt, được gọi là jQuery-pizer .

JavaScript pushStatevà jQuery có thể được sử dụng cùng nhau, như:

history.pushState(null, null, $(this).attr('href'));

Thí dụ:

$('a').click(function (event) {

  // Prevent default click action
  event.preventDefault();     

  // Detect if pushState is available
  if(history.pushState) {
    history.pushState(null, null, $(this).attr('href'));
  }
  return false;
});


Chỉ sử dụng JavaScript history.pushState() , thay đổi tham chiếu, được sử dụng trong tiêu đề HTTP cho các đối tượng XMLHttpRequest được tạo sau khi bạn thay đổi trạng thái.

Thí dụ:

window.history.pushState("object", "Your New Title", "/new-url");

Phương thức PushState ():

pushState()nhận ba tham số: một đối tượng trạng thái, một tiêu đề (hiện đang bị bỏ qua) và (tùy chọn) một URL. Hãy xem xét từng thông số trong ba thông số này một cách chi tiết hơn:

  1. đối tượng trạng thái - Đối tượng trạng thái là một đối tượng JavaScript được liên kết với mục lịch sử mới được tạo bởi pushState(). Bất cứ khi nào người dùng điều hướng đến trạng thái mới, một sự kiện popstate sẽ được kích hoạt và thuộc tính trạng thái của sự kiện chứa một bản sao của đối tượng trạng thái của mục lịch sử.

    Đối tượng trạng thái có thể là bất cứ điều gì có thể được nối tiếp. Vì Firefox lưu các đối tượng trạng thái vào đĩa của người dùng để chúng có thể được khôi phục sau khi người dùng khởi động lại trình duyệt của cô ấy, chúng tôi áp đặt giới hạn kích thước 640k ký tự trên biểu diễn tuần tự của một đối tượng trạng thái. Nếu bạn truyền một đối tượng trạng thái có biểu diễn tuần tự lớn hơn đối tượng này pushState(), phương thức sẽ đưa ra một ngoại lệ. Nếu bạn cần nhiều dung lượng hơn mức này, bạn nên sử dụng sessionStorage và / hoặc localStorage.

  2. tiêu đề - Firefox hiện bỏ qua tham số này, mặc dù nó có thể sử dụng nó trong tương lai. Truyền chuỗi rỗng ở đây sẽ an toàn trước các thay đổi trong tương lai của phương thức. Ngoài ra, bạn có thể chuyển một tiêu đề ngắn cho trạng thái mà bạn đang di chuyển.

  3. URL - URL của mục lịch sử mới được cung cấp bởi tham số này. Lưu ý rằng trình duyệt sẽ không tải URL này sau khi gọi đến pushState(), nhưng nó có thể cố gắng tải URL sau, chẳng hạn sau khi người dùng khởi động lại trình duyệt của mình. URL mới không cần phải tuyệt đối; nếu nó tương đối, nó được giải quyết liên quan đến URL hiện tại. URL mới phải có cùng nguồn gốc với URL hiện tại; nếu không, pushState()sẽ ném một ngoại lệ. Tham số này là tùy chọn; nếu không được chỉ định, nó được đặt thành URL hiện tại của tài liệu.



3

Thư viện ảnh của Facebook thực hiện việc này bằng cách sử dụng #hash trong URL. Dưới đây là một số URL ví dụ:

Trước khi nhấp vào 'tiếp theo':

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507

Sau khi nhấp vào 'tiếp theo':

/photo.php?fbid=496429237507&set=a.218088072507.133423.681812507&pid=5887027&id=681812507#!/photo.php?fbid=496435457507&set=a.218088072507.133423.681812507&pid=5887085&id=681812507

Lưu ý hàm băm (#!) Ngay sau đó là URL mới.



2

Những gì đang làm việc cho tôi là - history.replaceState()chức năng như sau -

history.replaceState(data,"Title of page"[,'url-of-the-page']);

Điều này sẽ không tải lại trang, bạn có thể sử dụng nó với sự kiện javascript


1

Tôi đã tự hỏi nếu nó sẽ hiển thị miễn là đường dẫn cha mẹ trong trang là như nhau, chỉ có một cái gì đó mới được thêm vào nó.

Vì vậy, giống như giả sử người dùng đang ở trang: http://domain.com/site/page.html Sau đó trình duyệt có thể cho phép tôi làm location.append = new.html và trang trở thành: http://domain.com/site/page.htmlnew.htmlvà trình duyệt không thay đổi.

Hoặc chỉ cho phép người đó thay đổi tham số, vì vậy hãy location.get = me=1&page=1.

Vì vậy, trang gốc trở thành http://domain.com/site/page.html?me=1&page=1và nó không làm mới.

Vấn đề với # là dữ liệu không được lưu trong bộ nhớ cache (ít nhất là tôi không nghĩ vậy) khi thay đổi hàm băm. Vì vậy, nó giống như mỗi lần một trang mới được tải, trong khi các nút quay lại và chuyển tiếp trong trang không phải Ajax có thể lưu trữ dữ liệu và không mất thời gian tải lại dữ liệu.

Từ những gì tôi thấy, lịch sử Yahoo đã tải tất cả dữ liệu cùng một lúc. Nó dường như không thực hiện bất kỳ yêu cầu Ajax nào. Vì vậy, khi a divđược sử dụng để xử lý thời gian làm thêm khác nhau, dữ liệu đó không được lưu trữ cho mỗi trạng thái lịch sử.


1

mã của tôi là:

//change address bar
function setLocation(curLoc){
    try {
        history.pushState(null, null, curLoc);
        return false;
    } catch(e) {}
        location.hash = '#' + curLoc;
}

Và hành động:

setLocation('http://example.com/your-url-here');

và ví dụ

$(document).ready(function(){
    $('nav li a').on('click', function(){
        if($(this).hasClass('active')) {

        } else {
            setLocation($(this).attr('href'));
        }
            return false;
    });
});

Đó là tất cả :)


1

Một câu trả lời đơn giản hơn tôi trình bày,

window.history.pushState(null, null, "/abc")

điều này sẽ thêm /abcsau tên miền trong URL trình duyệt. Chỉ cần sao chép mã này và dán mã vào bảng điều khiển trình duyệt và xem URL thay đổi thành " https://stackoverflow.com/abc "


0

Tôi đã thành công với:

location.hash="myValue";

Nó chỉ thêm #myValuevào URL hiện tại. Nếu bạn cần kích hoạt một sự kiện trên Tải trang, bạn có thể sử dụng tương tự location.hashđể kiểm tra giá trị liên quan. Chỉ cần nhớ xóa #khỏi giá trị được trả về bởi location.hashvd

var articleId = window.location.hash.replace("#","");
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.