2011-01-14 36 views
28

Do sau:cửa sổ bind popstate

$(window).bind("popstate", function() { 
    alert('popstate'); 
}); 

On tải đầu tiên, đám cháy báo động với FireFox và Chrome nhưng không Safari. Tại sao vậy? Bất cứ ai khác nhìn thấy điều này và biết làm thế nào để giải quyết tốt nhất cho điều này?

Cảm ơn

Trả lời

15

Tình huống hiện đã được đảo ngược. Chrome đã khắc phục lỗi và hiện đang kích hoạt popstate khi tải trang nhưng Firefox 4 (kể từ RC) đã khởi động từ thông số kỹ thuật và now does not fire popstate!

CẬP NHẬT: Thông số HTML5 đã được thay đổi vào năm 2011 thành trạng thái popstate không được kích hoạt khi tải trang. Cả Firefox và Chrome hiện đều làm điều đúng như Firefox 4 và Chrome 34.

+2

Thông số HTML5 đã được thay đổi vào năm 2011 thành trạng thái popstate không được kích hoạt khi tải trang. Https://code.google.com/p/chromium/issues/detail?id=63040 bỏ phiếu bầu chọn là cách tốt nhất để đưa Chrome trở lại tuân thủ tiêu chuẩn. Google đã biết trong hai năm hành vi của Chrome là không chính xác. – Dave

2

Đã xảy ra lỗi trong Webkit đã triển khai sai sự kiện "popstate". Hãy xem bài đăng đơn giản này giải thích sự cố (hiển thị và cho biết ít): http://www.bcherry.net/playground/pushstate

Đề xuất của tôi là triển khai trình theo dõi sự kiện "popstate" của riêng bạn cho Safari. Một cái gì đó như thế này:

$(window).load(function(){ 
    function fire_popstate(){ 
    $(this).trigger("popstate"); // fire it when the page first loads 
    } 
    var lasthash = window.location.hash; 
    setInterval(function(){ 
    var currenthash = window.location.hash; 
    if(lasthash != currenthash){ 
     fire_popstate(); 
    } 
    }, 500);//check every half second if the url has changed 
}); 

Bạn có thể bọc tuyên bố đó trong kiểm tra trình duyệt để kiểm tra safari. Thậm chí tốt hơn nếu "popstate" đã được kích hoạt khi DOM sẵn sàng và sau đó áp dụng hàm bên trong để thay thế việc triển khai thực hiện. Một điều bạn không muốn xảy ra là có hai sự kiện popstate được kích hoạt (nhân đôi logic xử lý sự kiện của bạn, cách tuyệt vời để khóa giao diện người dùng).

45

Xem mã từ pjax. pjax là thư viện nguồn mở khá phổ biến hiện nay, vì vậy logic dưới đây có thể là tốt nhất để tránh vấn đề này.

var popped = ('state' in window.history), initialURL = location.href 
$(window).bind('popstate', function(event) { 
    // Ignore inital popstate that some browsers fire on page load 
    var initialPop = !popped && location.href == initialURL 
    popped = true 
    if (initialPop) return 
    ... 

https://github.com/defunkt/jquery-pjax/blob/master/jquery.pjax.js

0

Đây là cách giải quyết của tôi.

window.setTimeout(function() { 
    window.addEventListener('popstate', function() { 
    // ... 
    }); 
}, 1000); 
+3

Điều này làm gì? Có lẽ thay vì đăng nó [ở khắp mọi nơi] (http://stackoverflow.com/a/8378425/74865) bạn nên nó giải thích nó cho một lần. – drozzy

+2

@drozzy Chắc chắn! Đoạn mã này thêm một trình nghe sự kiện mới vào sự kiện popstate (sau 1 giây). Với cách tiếp cận này, sự kiện popstate không được kích hoạt khi tải trang. – Baggz

+2

@Baggz, theo [demo của Dive vào html5] (http://diveintohtml5.info/examples/history/casey.html), '1 ms' là phù hợp hơn. –

17

Trong webkit sự kiện popstate được kích hoạt khi tải trang. Để tránh điều này, công việc này dễ dàng xung quanh việc cho tôi:

Mỗi lần tôi bắn history.push(...) tôi thêm các classhistorypushed đến body -tag:

history.push(...); 
$("body").addClass("historypushed"); 

Khi tôi kích hoạt các sự kiện popstate, tôi kiểm tra cho lớp học này:

$(window).bind('popstate', function(e) { 
if($("body").hasClass("historypushed")) { 
    /* my code */ 
} 
}); 
+0

Thông minh! Cảm ơn vì điều đó. – griffla

+0

Hoạt động tuyệt vời, cảm ơn! – tlaverdure

+0

giải pháp tốt đẹp :-) – milushov

3

Một cách dễ dàng để tránh vấn đề này là đặt đối số đầu tiên trên pushState thành true sau đó kiểm tra lại onpopstate. Tương tự như ví dụ pjax nhưng đơn giản hơn một chút. Ví dụ dưới đây sẽ chạy doSomething() cho mọi sự kiện popstate ngoại trừ tải trang đầu tiên.

function setupPopState() { 
    if (history.popState) { 
    # immediately replace state to ensure popstate works for inital page 
    history.replaceState(true, null, window.location.pathname); 

    $(window).bind('popstate', function(event) { 
     if (event.originalEvent.state) { 
     doSomething(); 
     } 
    }); 
    } 
} 
0

tôi chuyển đổi @Nobu & @Tamlyn câu trả lời vào một đối tượng, tôi cũng thêm một chút sửa chữa bằng cách thêm "window.history.state! == null". Trong một số trình duyệt, lịch sử history.state tồn tại, nhưng nó không có tác dụng nên nó không hoạt động.

/** 
 
* The HTML5 spec was changed in 2011 to state popstate should not 
 
* fired on page load. Chrome(34) & Firefox(4) has fixed the bug but 
 
* some browsers (e.g. Safari 5.1.7) are still fire the popstate on 
 
* the page load. This object created from the Pjax Library to handle 
 
* this issue. 
 
*/ 
 
var popstatePageloadFix = { 
 
\t popped : ('state' in window.history && window.history.state !== null), 
 
\t initialUrl : location.href, 
 
\t initialPop : false, 
 
\t init : function() { 
 
\t \t this.initialPop = !this.popped && location.href == this.initialUrl; 
 
\t \t this.popped = true; 
 
\t \t return this.initialPop; 
 
\t } 
 
}; 
 

 
$(window).on("popstate", function (event) { 
 
\t 
 
\t // Ignore initial popstate that some browsers fire on page load 
 
\t if (popstatePageloadFix.init()) return; 
 
\t 
 
\t ... 
 

 
});

Cảm ơn @Nobu! Cảm ơn @Tamlyn!

0

This answer to a similar question gợi ý để kiểm tra sự thật boolean của event.state trong xử lý popstate sự kiện:

window.addEventListener('popstate', function(event) { 
    if (event.state) { 
     alert('!'); 
    } 
}, false); 

Bạn cũng có thể buộc hàm callback của bạn để popstate sự kiện như thế này:

window.onpopstate = callback(); 

Kiểm tra here để biết thêm thông tin về giải pháp đó