开发者

Cross-browser jquery ajax history with window.history.pushState and fallback

Want to improve this post? Provide detailed answers to this question, including citations and an explanation of why your answer is correct. Answers without enough detail may be edited or deleted.

I want to implement a navigation history using jQuery and AJAX in a cross-browser manner. My a开发者_运维知识库pproach is to use window.history.pushState and fall back to a hash url /#!/url in browsers that do not support window.history.pushState.

For example:

<a href="/home">home</a>
<a href="/about">about</a>
<a href="/contact">contact</a>

On browsers that support window.history.pushState, clicking on one of these links should change address without page refresh to http://domain.com/home, http://domain.com/about etc. When the browser does not support window.history.pushState, it should use a fragment identifier, i.e: http://domain.com/#!/home, http://domain.com/#!/about.


Update: Based on the feedback here I have implemented Ajax SEO (git) that uses jQuery Address for HTML5 History API with old browser fallback to /#!/url.


// Assuming the path is retreived and stored in a variable 'path'

if (typeof(window.history.pushState) == 'function') {
    window.history.pushState(null, path, path);
} else {
    window.location.hash = '#!' + path;
}


Something i've been using with fallback hash URL's:

History = History || {};
History.pathname = null;
History.previousHash = null;
History.hashCheckInterval = -1;
History.stack = [];
History.initialize = function () {
    if (History.supportsHistoryPushState()) {
        History.pathname = document.location.pathname;
        $(window).bind("popstate", History.onHistoryChanged);
    } else {
        History.hashCheckInterval = setInterval(History.onCheckHash, 200);
    }
};
History.supportsHistoryPushState = function () {
    return ("pushState" in window.history) && window.history.pushState !== null;
};
History.onCheckHash = function () {
    if (document.location.hash !== History.previousHash) {
        History.navigateToPath(document.location.hash.slice(1));
        History.previousHash = document.location.hash;
    }
};
History.pushState = function (url) {
    if (History.supportsHistoryPushState()) {
        window.history.pushState("", "", url);
    } else {
        History.previousHash = url;
        document.location.hash = url;
    }
    History.stack.push(url);
};
History.onHistoryChanged = function (event) {
    if (History.supportsHistoryPushState()) {
        if(History.pathname != document.location.pathname){
            History.pathname = null;
            History.navigateToPath(document.location.pathname);
        }
    }
};
History.navigateToPath = function(pathname) {
    History.pushState(pathname);

    // DO SOME HANDLING OF YOUR PATH HERE

};

You could bind your click events to this with:

$(function(){
    $("a").click(function(){
        var href = $(this).attr('href');
        History.navigateToPath( href )
        return false;
    });
});

If you need some more explanation on this example i'll be glad to hear it.


EDIT

Please see my other answer.


It has been a while since my original answer and I would now suggest using Backbone.

An implementation could be:

// First setup a router which will be the responder for URL changes:
var AppRouter = Backbone.Router.extend({

  routes: {
    "*path": "load_content"
  },

  load_content: function(path){
    $('#content').load('/' + path);
  }

});
var appRouter = new AppRouter;

// Then initialize Backbone's history
Backbone.history.start({pushState: true});

Excerpt from the documentation:

To indicate that you'd like to use HTML5 pushState support in your application, use Backbone.history.start({pushState: true}). If you'd like to use pushState, but have browsers that don't support it natively use full page refreshes instead, you can add {hashChange: false} to the options.

And now every time Backbone.history.navigate is called, the AppRouter will perform an AJAX load of the path into the #content div.

To handle all links with AJAX you could use the following:

$("a").on('click', function(event){
    event.preventDefault();
    Backbone.history.navigate( event.currentTarget.pathname, {trigger: true} )
});

Take note of the {trigger: true} which causes the handler in the router to be called (otherwise only from url changes).

Fiddle with example code: http://jsfiddle.net/koenpunt/pkAz7/1/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜