HTML5 history API: cannot go backwards more than o

2019-09-08 05:57发布

问题:

I have been trying to get my script working but apparently there is something wrong with it: when I try to go backwards with the browser back button, it stops at the first page backwards i.e. the second time I click the back button, does not work properly and instead updates the current page with itself.

Examples: homepage -> second page -> third page -> second page -> second page -> second page (and so on)

homepage -> second page -> third page -> fourth page -> third page-> third page (and so on)

This instead works: homepage -> second page -> homepage

Does anyone have a clue to what I am missing?

var domain = 'http://example.com/';

function updatePage(json){
    var postData = JSON.parse(json);

    // pushState 
    var url = domain + postData.url;
    var title = postData.title;
    document.title = title;
    history.pushState({"page": url}, title, url);

    // Clears some elements and fills them with the new content
    // ...

    // Creates an 'a' element that triggers AJAX for the next post
    var a = document.createElement('a');
    a.innerHTML = postData.next;
    a.href = domain + postData.next;
    document.getElementById('container').appendChild( a );
    listenerAttacher( a );

    // Creates another 'a' element that triggers AJAX for the previous post
    a = document.createElement('a');
    a.innerHTML = postData.previous;
    a.href = domain + postData.previous;
    document.getElementById('container').appendChild( a );
    listenerAttacher( a );
}


function loadPost( resource ){
    // Loads post data through AJAX using a custom function
    loadHTML( resource, function(){
        updatePage( this.responseText );
    });
}

function listenerAttacher( element ){
    // Adds a click listener to an element. 
    element.addEventListener('click', function(e){
        e.preventDefault();
        e.stopPropagation();
        loadPost( this.href +'.json' );
        return false;
    }, 
    false);
}


(function(){
    history.replaceState({'page': window.location.href}, null, window.location.href);

    // Adds the event listener to all elements that require it.
    var titles = document.querySelectorAll('.post-title');
    for (var i = 0; i < titles.length; i++){
        listenerAttacher( titles[i] );
    }

    // Adds a popstate listener
    window.addEventListener('popstate', function(e){
        if ( e.state == null || e.state.page == domain ){
            window.location = domain;

        }
        else {
            loadPost( e.state.page + '.json' );
        }
    }, false);
})();

回答1:

When you pressed back button, popstate event is fired and loadPost function is called. However in loadPost, history.pushState method is called again, which pushes the current page on the history stack again. Which explains why the first back button works and then it does not.

1) A quick fix is to check if the current state matches the state you are trying to push:

if (!history.state || history.state.page!=url)
    history.pushState({ "page": url }, title, url);

2) Event better, you can add parameter to loadPost and updatePage functions to prevent unnecessary pushState calls:

function updatePage(json, disablePushState) {
    ...
    // disablePushState is true when back button is pressed
    // undefined otherwise
    if (!disablePushState)  
        history.pushState({ "page": url }, title, url);
    ...
}


function loadPost(resource, disablePushState) {
    // Loads post data through AJAX using a custom function
    loadHTML(resource, function (responseText) {
        updatePage(responseText, disablePushState);
    });
}

    ...
    window.addEventListener('popstate', function (e) {
        if (e.state == null || e.state.page == domain) {
            window.location = domain;
        }
        else {
            loadPost(e.state.page + '.json', true);
        }
        return true;
    });

Hope this help.