Trên - window.location.hash - Thay đổi?


558

Tôi đang sử dụng Ajax và hàm băm để điều hướng.

Có cách nào để kiểm tra nếu window.location.hashthay đổi như thế này?

http://example.com/blah # 123 đến http://example.com/blah # 456

Nó hoạt động nếu tôi kiểm tra nó khi tải tài liệu.

Nhưng nếu tôi có điều hướng dựa trên #hash thì nó không hoạt động khi tôi nhấn nút quay lại trên trình duyệt (vì vậy tôi chuyển từ blah # 456 sang blah # 123).

Nó hiển thị bên trong hộp địa chỉ, nhưng tôi không thể bắt nó bằng JavaScript.


6
Kiểm tra plugin jquery này: github.com/cowboy/jquery-hashchange
Xavi

9
History.js hỗ trợ Chức năng quản lý trạng thái HTML5 (vì vậy bạn không cần phải sử dụng băm nữa!) Và duyên dáng biến nó thành trình duyệt HTML4 bằng cách sử dụng hàm băm. Nó hỗ trợ jQuery, MooTools và Prototype.
balupton

@balupton, Trên thực tế, chúng tôi vẫn cần sử dụng băm để cung cấp phản hồi cho người dùng rằng "trang mới" đã được chèn vào lịch sử của anh ta, trừ khi bạn sử dụng thay đổi URL làm phản hồi.
Pacerier


hmm ... tôi nghĩ rằng bạn cần moar jQuery
RaisingAgent

Câu trả lời:


617

Cách duy nhất để thực sự làm điều này (và là cách 'reallysimplehistory' thực hiện điều này), bằng cách đặt một khoảng thời gian tiếp tục kiểm tra hàm băm hiện tại và so sánh nó với những gì trước đây, chúng tôi làm điều này và cho phép người đăng ký đăng ký thay đổi sự kiện chúng tôi kích hoạt nếu hàm băm thay đổi .. nó không hoàn hảo nhưng các trình duyệt thực sự không hỗ trợ sự kiện này nguyên bản.


Cập nhật để giữ cho câu trả lời này mới:

Nếu bạn đang sử dụng jQuery (mà ngày nay sẽ có phần nền tảng nhất) thì một giải pháp hay là sử dụng sự trừu tượng mà jQuery mang lại cho bạn bằng cách sử dụng hệ thống sự kiện của nó để lắng nghe các sự kiện băm trên đối tượng cửa sổ.

$(window).on('hashchange', function() {
  //.. work ..
});

Điều thú vị ở đây là bạn có thể viết mã mà không cần phải lo lắng về hỗ trợ hashchange, tuy nhiên bạn KHÔNG cần phải thực hiện một số phép thuật, dưới dạng một sự kiện đặc biệt ít được biết đến của jQuery .

Với tính năng này, về cơ bản bạn có thể chạy một số mã thiết lập cho bất kỳ sự kiện nào, lần đầu tiên ai đó cố gắng sử dụng sự kiện này theo bất kỳ cách nào (chẳng hạn như ràng buộc với sự kiện).

Trong mã thiết lập này, bạn có thể kiểm tra hỗ trợ trình duyệt riêng và nếu trình duyệt không thực hiện điều này, bạn có thể thiết lập một bộ đếm thời gian để thăm dò các thay đổi và kích hoạt sự kiện jQuery.

Điều này hoàn toàn không ràng buộc mã của bạn cần phải hiểu vấn đề hỗ trợ này, việc triển khai một sự kiện đặc biệt thuộc loại này là không đáng kể (để có được một phiên bản hoạt động 98% đơn giản), nhưng tại sao lại làm như vậy khi đã có người khác .


7
IE8 nào. Còn nhiều nữa
Serge Ilinsky

28
Bản dựng Firefox mới nhất (3.6 alpha) hiện cũng hỗ trợ sự kiện thay đổi hàm băm gốc: developer.mozilla.org/en/DOM/window.onhashchange Chắc chắn nên kiểm tra sự kiện này, nhưng lưu ý rằng IE8 sẽ cho bạn biết sự kiện tồn tại khi nó đang chạy trong chế độ compat IE7 .. thật đáng buồn là sự kiện không kích hoạt .. bạn sẽ cần kiểm tra sự kiện và trình duyệt không xuất hiện là IE7 .. thở dài (hoặc cố gắng kích hoạt sự kiện với phương pháp fireEvent của IE).
meandmycode

8
Tại thời điểm viết bài, WebKit cũng kích hoạt hashchangesự kiện, trong khi Safari (ổn định) chưa có.
jholster

51
Chỉ cần thêm một bản cập nhật khác, hashchangesự kiện này hiện được hỗ trợ rộng rãi: caniuse.com/#search=hash
Paystey

19
Tôi có phải là người duy nhất nghĩ rằng câu trả lời jQuery không được yêu cầu là một nỗi đau không?
Lục

290

HTML5 chỉ định một hashchangesự kiện . Sự kiện này hiện được hỗ trợ bởi tất cả các trình duyệt hiện đại . Hỗ trợ đã được thêm vào trong các phiên bản trình duyệt sau:

  • Internet Explorer 8
  • Firefox 3.6
  • Chrome 5
  • Safari 5
  • Opera 10.6

20
Cập nhật: FF 5, Safari 5 và Chrome 12 hỗ trợ sự kiện này kể từ tháng 6 năm 2011
james.garriss

2
Đây là trang CanIUse cho hashchange . Đây là hashchange trên quirksmode . Hỗ trợ IE là lỗi liên quan đến độ nhạy trường hợp.
Tobu

3
@everybody, không cần phải tiếp tục thêm câu trả lời trong phần bình luận - đó là nút "Chỉnh sửa" để làm gì. :)
Michael Martin-Smucker

15
cách sử dụng:window.onhashchange = function() { doYourStuff(); }
Chris

4
Tài liệu MDN của sự kiện hashchange .
Dabowheel

52

Lưu ý rằng trong trường hợp Internet Explorer 7 và Internet Explorer 9, thống kê ifsẽ cho đúng (đối với "onhashchange" trong các cửa sổ), nhưng window.onhashchangesẽ không bao giờ kích hoạt, vì vậy tốt hơn là lưu trữ hàm băm và kiểm tra sau mỗi 100 mili giây xem nó có thay đổi hay không cho tất cả các phiên bản của Internet Explorer.

    if (("onhashchange" in window) && !($.browser.msie)) {
         window.onhashchange = function () {
              alert(window.location.hash);
         }
         // Or $(window).bind( 'hashchange',function(e) {
         //       alert(window.location.hash);
         //   });
    }
    else {
        var prevHash = window.location.hash;
        window.setInterval(function () {
           if (window.location.hash != prevHash) {
              prevHash = window.location.hash;
              alert(window.location.hash);
           }
        }, 100);
    }

EDIT - Vì jQuery 1.9, $.browser.msiekhông được hỗ trợ. Nguồn: http://api.jquery.com/jquery.browser/


14

Có rất nhiều thủ thuật để đối phó với Lịch sử và window.location.hash trong trình duyệt IE:

  • Như câu hỏi ban đầu đã nói, nếu bạn đi từ trang a.html # b đến a.html # c, rồi nhấn nút quay lại, trình duyệt không biết rằng trang đó đã thay đổi. Hãy để tôi nói điều đó với một ví dụ: window.location.href sẽ là 'a.html # c', bất kể bạn đang ở a.html # b hay a.html # c.

  • Trên thực tế, a.html # b và a.html # c được lưu trữ trong lịch sử chỉ nếu các yếu tố '<a name="#b">' và '<a name="#c">' tồn tại trước đó trong trang.

  • Tuy nhiên, nếu bạn đặt iframe bên trong trang, hãy điều hướng từ a.html # b đến a.html # c trong iframe đó và sau đó nhấn nút quay lại, iframe.contentWindow.document.location.href thay đổi như mong đợi.

  • Nếu bạn sử dụng 'document.domain = cái gì đó ' trong mã của bạn, sau đó bạn không truy cập vào iframe.contentWindow.document.open ()' có thể (và nhiều nhà quản lý Lịch sử nào đó)

Tôi biết đây không phải là một phản hồi thực sự, nhưng có lẽ các ghi chú Lịch sử IE là hữu ích cho ai đó.




9

Bạn có thể dễ dàng thực hiện một trình quan sát (phương thức "xem") trên thuộc tính "băm" của đối tượng "window.location".

Firefox có triển khai riêng để xem các thay đổi của đối tượng , nhưng nếu bạn sử dụng một số triển khai khác (chẳng hạn như Xem các thay đổi thuộc tính đối tượng trong JavaScript ) - đối với các trình duyệt khác, điều đó sẽ thực hiện thủ thuật.

Mã sẽ trông như thế này:

window.location.watch(
    'hash',
    function(id,oldVal,newVal){
        console.log("the window's hash value has changed from "+oldval+" to "+newVal);
    }
);

Sau đó, bạn có thể kiểm tra nó:

var myHashLink = "home";
window.location = window.location + "#" + myHashLink;

Và tất nhiên điều đó sẽ kích hoạt chức năng quan sát viên của bạn.


Sử dụng tốt hơn: window.location.href thay vì window.location.
Codebeat

3
Anh ấy đang xem window.location.hash, không phải window.location.
không xác định

1
@BrianMortenson: theo các tài liệu ( developer.mozilla.org/en-US/docs/JavaScript/Reference/ trộm ) bạn phải áp dụng watchcho đối tượng sở hữu tài sản đang thay đổi và bạn muốn quan sát nó.
gion_13

@ gion_13 Vâng, đó chính xác là những gì tôi đã cố gắng chỉ ra. "Anh ấy" ý tôi là bạn, và nó được hướng vào bình luận của Erwinus. Tôi cần phải có được rõ ràng hơn. Cảm ơn bạn đã bình luận làm rõ.
không xác định

7

Tôi đã sử dụng điều này trong một ứng dụng phản ứng để làm cho URL hiển thị các tham số khác nhau tùy thuộc vào chế độ xem của người dùng.

Tôi đã xem tham số băm bằng cách sử dụng

window.addEventListener('hashchange', doSomethingWithChangeFunction());

Sau đó

doSomethingWithChangeFunction () { 
    // Get new hash value
    let urlParam = window.location.hash;
    // Do something with new hash value
};

Đã xử lý, làm việc với các nút trình duyệt tiến và lùi và cả trong lịch sử trình duyệt.


1
trong addEventListenercuộc gọi của bạn , bạn nên xóa ()từdoSomethingWithChangeFunction
Jason S

Bạn có thể cung cấp một lý do để loại bỏ ()? Tôi biết nó sẽ hoạt động với một trong hai, và ít mã hơn chủ yếu là tùy chọn tốt hơn, nhưng điều này có vẻ kén chọn trừ khi có lý do đáng kể để sao lưu này?
Sprose

6
? nó không nên làm việc với (). Các addEventListenerchức năng đòi hỏi bạn phải vượt qua trong một hàm. doSomethingWithChangeFunctionlà một chức năng. doSomethingWithChangeFunction()là giá trị trả về của hàm đó, trong trường hợp này không phải là hàm.
Jason S

6

Một triển khai tốt có thể được tìm thấy tại http://code.google.com.vn/p/reallysimplehistory/ . Vấn đề duy nhất (nhưng cũng) và lỗi của nó là: trong Internet Explorer sửa đổi vị trí băm thủ công sẽ đặt lại toàn bộ ngăn xếp lịch sử (đây là sự cố trình duyệt và không thể giải quyết được).

Lưu ý, Internet Explorer 8 có hỗ trợ cho sự kiện "hashchange" và vì nó đang trở thành một phần của HTML5, bạn có thể mong đợi các trình duyệt khác bắt kịp.


1

Một triển khai tuyệt vời khác là Lịch sử jQuery sẽ sử dụng sự kiện onhashchange riêng nếu được trình duyệt hỗ trợ, nếu không, nó sẽ sử dụng iframe hoặc khoảng thích hợp cho trình duyệt để đảm bảo tất cả các chức năng dự kiến ​​được mô phỏng thành công. Nó cũng cung cấp một giao diện đẹp để liên kết với các trạng thái nhất định.

Một dự án khác cũng đáng chú ý là jQuery Aj Wax , đây là phần mở rộng cho Lịch sử jQuery để thêm ajax vào hỗn hợp. Như khi bạn bắt đầu sử dụng ajax với băm, nó khá phức tạp !


1
var page_url = 'http://www.yoursite.com/'; // full path leading up to hash;
var current_url_w_hash = page_url + window.location.hash; // now you might have something like: http://www.yoursite.com/#123

function TrackHash() {
    if (document.location != page_url + current_url_w_hash) {
        window.location = document.location;
    }
    return false;
}
var RunTabs = setInterval(TrackHash, 200);

Đó là ... bây giờ, bất cứ khi nào bạn nhấn nút quay lại hoặc chuyển tiếp, trang sẽ tải lại theo giá trị băm mới.


không sử dụng chuỗi eval
Vitim.us

1

Tôi đã sử dụng path.js để định tuyến phía máy khách của mình. Tôi đã thấy nó khá ngắn gọn và gọn nhẹ (nó cũng được xuất bản cho NPM) và sử dụng điều hướng dựa trên hàm băm.

NPM path.js

path.js GitHub


0

Tôi đã sử dụng một plugin jQuery, HUtil và đã viết một giao diện YUI History giống như trên nó.

Kiểm tra nó một lần. Nếu bạn cần giúp đỡ, tôi có thể giúp.

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.