带有history.pushState和popstate的Ajax - 当popstate state属性为null时,我该怎么办? [英] Ajax with history.pushState and popstate - what do I do when popstate state property is null?

查看:126
本文介绍了带有history.pushState和popstate的Ajax - 当popstate state属性为null时,我该怎么办?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ajax加载内容的HTML5历史记录API。

I'm trying out the HTML5 history API with ajax loading of content.

我有一堆通过相关链接连接的测试页面。我有这个JS,它处理这些链接的点击。当单击链接时,处理程序获取其href属性并将其传递给ajaxLoadPage(),该页面将所请求页面中的内容加载到当前页面的内容区域中。 (我的PHP页面设置为在正常请求时返回完整的HTML页面,但只有一小部分内容,如果?fragment = true附加到请求的URL。)

I've got a bunch of test pages connected by relative links. I have this JS, which handles clicks on those links. When a link is clicked the handler grabs its href attribute and passes it to ajaxLoadPage(), which loads content from the requested page into the content area of the current page. (My PHP pages are set up to return a full HTML page if you request them normally, but only a chunk of content if ?fragment=true is appended to the URL of the request.)

然后我的点击处理程序调用history.pushState()以在地址栏中显示URL并将其添加到浏览器历史记录中。

Then my click handler calls history.pushState() to display the URL in the address bar and add it to the browser history.

$(document).ready(function(){

    var content = $('#content');

    var ajaxLoadPage = function (url) {
        console.log('Loading ' + url + ' fragment');
        content.load(url + '?fragment=true');
    }

    // Handle click event of all links with href not starting with http, https or #
    $('a').not('[href^=http], [href^=https], [href^=#]').on('click', function(e){

        e.preventDefault();
        var href = $(this).attr('href');
        ajaxLoadPage(href);
        history.pushState({page:href}, null, href);

    });

    // This mostly works - only problem is when popstate happens and state is null
    // e.g. when we try to go back to the initial page we loaded normally
    $(window).bind('popstate', function(event){
        console.log('Popstate');
        var state = event.originalEvent.state;
        console.log(state);
        if (state !== null) {
            if (state.page !== undefined) {
                ajaxLoadPage(state.page);
            }
        }
    });

});

使用pushState向历史记录添加URL时,还需要为popstate事件包含事件处理程序处理后退或前进按钮的点击。 (如果你不这样做,点击后面会显示你在地址栏中推送到历史记录的URL,但页面没有更新。)所以我的popstate处理程序抓取保存在我创建的每个条目的state属性中的URL,并将其传递给ajaxLoadPage以加载适当的内容。

When you add URLs to the history with pushState you also need to include an event handler for the popstate event to deal with clicks on the back or forward buttons. (If you don't do this, clicking back shows the URL you pushed to history in the address bar, but the page isn't updated.) So my popstate handler grabs the URL saved in the state property of each entry I created, and passes it to ajaxLoadPage to load the appropriate content.

这对我的点击处理程序添加到历史记录中的页面有效。但是,当我正常请求浏览器时,浏览器添加到历史记录的页面会发生什么?假设我正常登陆我的第一页,然后通过点击进行ajax加载浏览我的网站 - 如果我然后尝试返回历史记录到第一页,最后一次点击显示第一页的URL,但不是不要在浏览器中加载页面。为什么会这样?

This works OK for pages my click handler added to the history. But what happens with pages the browser added to history when I requested them "normally"? Say I land on my first page normally and then navigate through my site with clicks that do that ajax loading - if I then try to go back through the history to that first page, the last click shows the URL for the first page, but doesn't load the page in the browser. Why is that?

我可以看到这与最后一个popstate事件的state属性有关。对于该事件,state属性为null,因为它只是由pushState()或replaceState()添加到历史记录中的条目,可以为其赋值。但我第一次加载页面是一个正常的请求 - 为什么浏览器不会退回并正常加载初始URL?

I can sort of see this has something to do with the state property of that last popstate event. The state property is null for that event, because it's only entries added to the history by pushState() or replaceState() that can give it a value. But my first loading of the page was a "normal" request - how come the browser doesn't just step back and load the initial URL normally?

推荐答案

我仍然不明白为什么后退按钮的行为如此 - 我以为浏览器会很高兴回到正常请求创建的条目。也许当您使用pushState插入其他条目时,历史记录将以正常方式停止运行。但我发现了一种让我的代码更好的方法。您不能始终依赖包含要返回的URL的state属性。但是,回过头历史可以像预期的那样更改地址栏中的URL,因此基于window.location加载内容可能更可靠。在很好的示例之后,我更改了我的popstate处理程序,以便根据地址栏中的URL加载内容而不是在州属性中查找URL。

I still don't understand why the back button behaves like this - I'd have thought the browser would be happy to step back to an entry that was created by a normal request. Maybe when you insert other entries with pushState the history stops behaving in the normal way. But I found a way to make my code work better. You can't always depend on the state property containing the URL you want to step back to. But stepping back through history changes the URL in the address bar as you would expect, so it may be more reliable to load your content based on window.location. Following this great example I've changed my popstate handler so it loads content based on the URL in the address bar instead of looking for a URL in the state property.

有一点需要注意的是,有些浏览器(如Chrome)会在您最初点击时触发一个popstate事件页面。发生这种情况时,您可能会不必要地重新加载初始页面的内容。所以我从优秀的 pjax 中添加了一些代码来忽略最初的流行音乐。

One thing you have to watch out for is that some browsers (like Chrome) fire a popstate event when you initially hit a page. When this happens you're liable to reload your initial page's content unnecessarily. So I've added some bits of code from the excellent pjax to ignore that initial pop.

$(document).ready(function(){

    // Used to detect initial (useless) popstate.
    // If history.state exists, pushState() has created the current entry so we can
    // assume browser isn't going to fire initial popstate
    var popped = ('state' in window.history && window.history.state !== null), initialURL = location.href;

    var content = $('#content');

    var ajaxLoadPage = function (url) {

        console.log('Loading ' + url + ' fragment');
        content.load(url + '?fragment=true');

    }

    // Handle click event of all links with href not starting with http, https or #
    $('a').not('[href^=http], [href^=https], [href^=#]').on('click', function(e){

        e.preventDefault();
        var href = $(this).attr('href');
        ajaxLoadPage(href);
        history.pushState({page:href}, null, 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;

        console.log('Popstate');

        // By the time popstate has fired, location.pathname has been changed
        ajaxLoadPage(location.pathname);

    });

});

您可以对此JS进行的一项改进只是在浏览器支持时附加click事件处理程序历史API。

One improvement you could make to this JS is only to attach the click event handler if the browser supports the history API.

这篇关于带有history.pushState和popstate的Ajax - 当popstate state属性为null时,我该怎么办?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆