pushState()和popState():操作浏览器历史记录

6
我正在开发一个小项目,想要创建一个Ajax风格的网站。使用jQuery的load()加载内容。正如你们中的一些人所知道的那样,这种方法的缺点是URL不会根据显示的内容相应地改变。为了使其工作,可以使用pushState()。但由于它不支持跨浏览器,我使用了插件history.js
这个方法运行得很好,但问题是我的后退和前进按钮没有按照预期工作,我不知道自己做错了什么。URL和内容都正确地改变了,但标题却没有改变。这里的标题指的是浏览器窗口的标题(或选项卡)所显示的内容。也就是被加载页面的<title>标签或者链接的title属性(它们是相同的)。我认为这可能与我只调用需要的页面部分有关(通过在load()中添加#content)。但我仍然想要该页面的标题。以下是我到目前为止的测试案例。(自2013年12月28日起不再提供。)jQuery文件:
$(document).ready(function () {
    var firstLink = $("ul > li:first-child > a");
    var menuLink = $("ul > li > a");
    var firstLoadedHtml = firstLink.attr("href") + " #content";

    $("#sectionContainer").hide().load(firstLoadedHtml).fadeIn("fast");
    firstLink.addClass("active");   

    menuLink.click(function(e) {
        history.pushState(null, null, this.href);

        e.preventDefault();
        e.stopImmediatePropagation();

        var CurLink = $(this);
        var newLoadedHtml = CurLink.attr("href") + " #content";
        var oldSection = $(".contentPage");

        $("#sectionContainer").hide().load(newLoadedHtml).fadeIn("fast");
        menuLink.removeClass("active");
        CurLink.addClass("active");
    });

    $(window).bind('popstate', function() {
            var returnLocation = history.location || document.location;

            $('#sectionContainer').load(returnLocation + "#content");
    });
});

我注意到当返回基本页面(即/sectionLoaderTest/)时,它会在一段时间内变成空白,只有一段时间后才会加载第一页的内容。有没有办法优化这个问题?
此外,我正在使用jQuery为被点击的链接添加一个active-class。如何确保这随着历史记录而相应更改?这样当用户导航回来时,正确的链接将被突出显示?
所以这三个问题是:
1.让标题在前进和后退时正常工作 2.优化主页面的加载时间 3.修复前进和后退时的active-class
欢迎任何帮助!
注1:我想建立在history.js和我的自己的脚本之上,并且因此保持对< HTML5浏览器的支持。我更喜欢这种方法,因为1.我知道这必须起作用,只是有些事情出了问题。2.如果我能看到别人的解决方案并在我已经编写的脚本中实现它,那么这将节省时间,而不是想出一个全新的脚本。
注2:只有回答我所有问题(3)的人才会得到赏金!

你还不会吗?看这个例子:https://dev59.com/p2w15IYBdhLWcg3wbLLU#9470183 - devote
你的评论并没有真正帮到我。我现在不需要实现history.js,我只是想要理解pushState正在做什么。我想要解决这个问题。 - Bram Vanroy
我的评论指出了你的错误,关于处理事件的方法。你所发布的拦截事件popstate的方法是不正确的,在点击时将其从方法中移除。 - devote
添加了history.js,仍然无法工作。 - Bram Vanroy
标题指的是浏览器窗口(或选项卡)的标题。即加载的页面的<title>或引用该页面的链接的title属性(它们是相同的)。 - Bram Vanroy
2个回答

11

答案1 - 在前后导航时使标题生效

据我理解,您想要在加载到一个 div 中的链接中更改文档标题 html。当您通过 jQuery 的 .load 加载文件到 div 中时,您只是将完整的响应文本插入 ajax 请求之后的位置。因此,在像 titlemeta 标签等不应该出现在 div 中的所有内容中都包含着。但是,当前文档 (http://bramvanroy.be/sectionLoaderTest/index.html) 的标题定义在 head 标签内的 title 中,而不是在 div 中的 title 标签中,这就是为什么文档标题没有更改的原因。

那我该如何解决呢?

好问题,因为在 div 元素内的 title 元素无效,大多数浏览器都会将其删除,所以您不能仅使用以下代码:

document.title = $("#sectionContainer title").text();

因为可能不存在 title 元素。

所以我们需要的是 jQuery .load 函数的直接响应。可以通过向函数添加回调参数来获得它:

$("#sectionContainer")
    .hide()
    .load(newLoadedHtml, function(responseText) {
        document.title = $(responseText).filter("title").text();
    })
    .fadeIn("fast");
你可能不理解为什么我使用.filter而不是.find函数。这是因为jQuery会从HTML中解析出htmlheadbody标签,但不会移除它们的子元素。
答案2-优化主页面的加载时间
文档从顶部到底部加载。
首先应该加载CSS、JavaScript等,然后才是主要文档。 因为jQuery总是在文档加载之前等待执行,所以把所有的script元素放在结束前并不是一个非常糟糕的想法,这样可以在HTML加载之前加载脚本。
顺便说一下,我第一次遇到这个问题后,一切都被缓存了,文档加载非常快。
答案3-在向前和向后进行操作时修复活动类(active-class)
我建议循环遍历a元素的href属性,并将其与History.getState()的数据进行比较。应该很容易实现。
你在代码中犯了一些错误-你的修复代码:
你附加了哈希#content到所有的URL上...这没有意义,而且它会被jQuery再次删除:https://github.com/jquery/jquery/blob/master/src/ajax.js#L617 (来自行: 158, 190, 337, 617- rhash在第6行)
$(document).ready(function () {
    var firstLink = $("ul > li:first-child > a");
    var menuLink = $("ul > li > a");
    var firstLoadedHtml = firstLink.attr("href");

    $("#sectionContainer").hide().load(firstLoadedHtml).fadeIn("fast");
    firstLink.addClass("active");   

    menuLink.click(function(e) {

        e.preventDefault();
        e.stopImmediatePropagation();

        var newLoadedHtml = $(this).attr("href");

        History.pushState(null, newLoadedHtml, newLoadedHtml);

        $("#sectionContainer")
            .hide()
            .load(newLoadedHtml, function(responseText) {
                document.title = $(responseText).filter("title").text();
            })
            .fadeIn("fast");
    });

    History.Adapter.bind(window, "statechange", function() {
        menuLink.removeClass("active");
        $("a[href='" + History.getState().title + "']").addClass("active");
        $('#sectionContainer').load(document.location.href, function(responseText) {
            document.title = $(responseText).filter("title").text();
        }); 
    });
});

我可能错过了什么(同时忙于许多事情),但它不起作用。标题更改为第一个和最后一个链接中定义的“包含”中定义的标题。而且(更重要的是),返回按钮不再更改内容。我有一种感觉,我正在忽略一个非常基本的东西。测试用例已被编辑:http://bramvanroy.be/sectionLoaderTest/ - Bram Vanroy
1
最终,我进行了新的编辑,它将起作用!已测试即使正确的链接也将始终具有类active - noob
确实有效,非常感谢您!还有一个问题(我无论如何都会给您+100 - 不用担心):菜单及其切换由cookie控制。但出于某种原因,“cookie”对象被删除了。您可以通过执行以下操作来尝试此操作:单击随机链接,隐藏面板,转到上一页,然后再次尝试打开面板。检查控制台以获取详细信息。非常奇怪!我不知道所有这些摆弄对网站的cookie产生什么影响...您认为这可以修复吗?感谢一切! - Bram Vanroy
@BramVanroy 哦,是的,你说得对。我忘记给第二个.load函数添加回调函数了。 - noob
让我们在聊天中继续这个讨论。 (Let us continue this discussion in chat.) - Bram Vanroy
显示剩余2条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接