jQuery pushState() 和 popState():操纵浏览器的历史记录
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10632483/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
pushState() and popState(): manipulating browsers' history
提问by Bram Vanroy
I am working on a small project in which I want to create an Ajax-style website. Content is loaded with jQuery's load()
. As some of you know, the down side of this is that the URL does not change accordingly to the content that is displayed. To make this work you can use pushState()
. Because this is not cross-browser supported, I used the plug-in history.js
.
我正在做一个小项目,我想在其中创建一个 Ajax 风格的网站。内容使用 jQuery 的load()
. 正如你们中的一些人所知,这样做的缺点是 URL 不会根据显示的内容而相应地更改。要完成这项工作,您可以使用pushState()
. 因为这不支持跨浏览器,所以我使用了插件history.js
.
This is working quite nicely, but the problem is that my back and forward buttons are not working as they should and I have no idea what I am doing wrong. The URL is changing correctly and the content is as well, but the title is not changing at all. With title I mean what is shown as title of the window (or tab) of the browser window. I.e. the <title>
of the page that is loaded OR the title attribute of the link that refers to that page (they are the same). I think it has to do with the fact that I call only a section of the page whose title I need (i.e. by adding #content
to the load()
). I still want the title of that page though. Here is a test case of what I have up to now. (Not available any more since 28 Dec. 2013.) jQuery file:
这工作得很好,但问题是我的后退和前进按钮无法正常工作,我不知道我做错了什么。URL 正确更改,内容也正确更改,但标题根本没有更改。标题是指显示为浏览器窗口的窗口(或选项卡)标题的内容。即<title>
加载的页面的或引用该页面的链接的标题属性(它们是相同的)。我认为这与我只调用我需要其标题的页面部分的事实有关(即通过添加#content
到load()
)。我仍然想要那个页面的标题。这是我目前所拥有的测试用例。(自 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");
});
});
I also noted that when going back to the basic page (i.e. /sectionLoaderTest/) it goes blank for a while and only after a while the content of the first page is loaded. Is there a way to optimize this?
我还注意到,当返回到基本页面(即 /sectionLoaderTest/)时,它会暂时空白,并且仅在一段时间后加载第一页的内容。有没有办法优化这个?
Additionally, I am using jQuery to add an active-class to the link that has been clicked. How can I make sure that this changes accordingly to the history? So that the correct link is highlighted when a user navigates back?
此外,我正在使用 jQuery 向已单击的链接添加活动类。我怎样才能确保这会根据历史发生变化?以便在用户返回时突出显示正确的链接?
So the three questions are:
所以三个问题是:
- Get the title working when going forward and backward
- Optimize the load time of the mainpage
- Fix the active-class when going forward and backward
- 前进和后退时获得标题工作
- 优化主页加载时间
- 修复前进和后退时的活动类
All help welcome!
欢迎所有帮助!
NOTE 1: I would like to build on history.js and my own script and as such keep support for < HTML5
browsers. I would prefer this because 1. I know this has to work, there is just something that's going wrong. 2. It would save time if I could see one's solution and implement it in the script I already wrote rather than figuring out a whole new script.
注意 1:我想建立在 history.js 和我自己的脚本上,因此保持对< HTML5
浏览器的支持。我更喜欢这个,因为 1. 我知道这必须起作用,只是出了点问题。2. 如果我能看到一个人的解决方案并在我已经编写的脚本中实现它,而不是找出一个全新的脚本,这将节省时间。
NOTE 2: The bounty will only be given to he or she who can answer all of my questions (3)!
注意 2:赏金只会给能够回答我所有问题的人(3)!
回答by noob
Answer 1 - Get the title working when going forward and backward
答案 1 - 让标题在前进和后退时起作用
As far as I understood you want to change the document title html from the link is loaded in a div. When you're loading a file in a div via jQuery .load
you're just inserting the complete response text after an ajax request in it. So with all the stuff which shouldn't be in a div like the title
or meta
tag. However the title of the current document (http://bramvanroy.be/sectionLoaderTest/index.html
) is defined in the title
which is inside the head
tag and not in the title
tag inside a div so that's why the document title doesn't change.
据我了解,您要更改链接中的文档标题 html 加载到 div 中。当您通过 jQuery 在 div 中加载文件时,.load
您只是在其中的 ajax 请求之后插入完整的响应文本。所以所有不应该在 div 中的东西,比如title
ormeta
标签。然而,当前文档 ( http://bramvanroy.be/sectionLoaderTest/index.html
)的标题title
是在head
标签内的which 中定义的,而不是在title
div内的标签中,所以这就是文档标题不会改变的原因。
So how can I fix it?
那么我该如何解决呢?
Good question, because the title
element inside a div
element is invalid, most browsers will remove it so you can't just use this:
好问题,因为title
元素内的div
元素无效,大多数浏览器都会删除它,所以你不能只使用这个:
document.title = $("#sectionContainer title").text();
because the title
element may not exist.
因为该title
元素可能不存在。
So what we need is the direct response from the jQuery .load
function. I can get it by adding the callback argument to the function:
所以我们需要的是来自 jQuery.load
函数的直接响应。我可以通过向函数添加回调参数来获取它:
$("#sectionContainer")
.hide()
.load(newLoadedHtml, function(responseText) {
document.title = $(responseText).filter("title").text();
})
.fadeIn("fast");
What you may not understand is why I use the .filter
and not the .find
function. This is because jQuery is kind of parsing html
, head
and body
tags out of the html but not removing there child elements.
你可能不明白为什么我使用了.filter
而不是.find
函数。这是因为 jQuery 是一种解析html
,head
并且body
标记出 html 但不会删除那里的子元素。
Answer 2 - Optimize the load time of the mainpage
答案 2 - 优化主页的加载时间
A document is getting loaded from to top to the bottom.
文档从上到下加载。
So first of all the css, JavaScript etc. should be loaded and then the the main document.
Because jQuery is always waiting for the document before it's executing it wouldn't be a very bad idea to put all your script
elements right before the end of the body, so that your HTML can be loaded before.
所以首先应该加载 css、JavaScript 等,然后是主文档。因为 jQuery 总是在执行之前等待文档,所以将所有script
元素放在正文末尾之前并不是一个非常糟糕的主意,以便您的 HTML 可以在之前加载。
BtW I just had this problem at the first time after that everything was cached and the document was loading very fast.
顺便说一句,在所有内容都被缓存并且文档加载非常快之后,我第一次遇到了这个问题。
Answer 3 - Fix the active-class when going forward and backward
答案 3 - 在前进和后退时修复 active-class
I would say loop trough the href
attributes of the a
elements and compare it with the data from History.getState()
. Should be easy.
我会说循环遍历元素的href
属性a
并将其与History.getState()
. 应该很容易。
You did some mistakes in your code - Your fixed code:
您在代码中犯了一些错误 - 您的固定代码:
You appended the hash #content
to all URLs.. it doesn't make sense and it will be removed by jQuery again: https://github.com/jquery/jquery/blob/master/src/ajax.js#L617(Comes from lines: 158, 190, 337, 617 - rhash is on line 6)
您将哈希附加#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();
});
});
});
回答by Deepak Thomas
You could also try available routing plugins like davis.jsor jQuery Pusherhttps://github.com/salvan13/jquery-pusher
您还可以尝试可用的路由插件,如davis.js或jQuery Pusher https://github.com/salvan13/jquery-pusher