我正在开发一个通过AJAX提供内容的网站.
如果单击菜单中的某个项目,内容div将更新为$.get响应,没有任何花哨.
我正在实现history.pushState允许使用浏览器的后退/前进按钮进行导航.
我有以下内容在历史导航中加载内容:
$(function() {
$(window).bind("popstate", function() {
$.getScript(location.href);
});
});
Run Code Online (Sandbox Code Playgroud)
问题是,当第一次加载页面时,此功能会$.getScript立即再次加载页面.第一次加载页面时,它会呈现初始HTML视图,然后在第二次加载时呈现JS视图,因为它是一个JS请求.
如何防止此事件在具有HTML请求的页面上触发?
我们的一些链接由PJAX包装.当用户单击PJAX链接时,服务器仅返回HTML的必需部分.
如果我执行以下操作:
浏览器将显示PJAX请求返回的内容.HTML将被破坏,因为它只是要显示的HTML的一部分(请查看此问题).
我们试图通过不缓存PJAX响应(Cache-Control标题)来解决这个问题.这解决了我们的问题,但提出了另一个问题:当用户按下后退按钮时,WebKit(Chrome 20.0)从服务器加载完整内容,然后触发popstate导致不必要的PJAX请求的事件.
是否可以重新创建正确的后退按钮行为?
我试图阻止用户回到我的网络应用程序.为此,我尝试捕获window.onpopstate并添加e.preventDefault以取消后退按钮效果.
但它似乎没有发生.
window.addEventListener('popstate',function(e){
console.log(e); e.preventDefault();
});
Run Code Online (Sandbox Code Playgroud)
是否无法阻止浏览器的popstate事件?或者我做错了什么?
我一直试图让前面的浏览器按钮在一个小网站上使用pjax工作,并提出以下代码来处理类更改和淡入淡出各种叠加层.
但是我发现Chrome和Safari将初始页面加载视为popstate,因此它让我感到悲伤.反正有没有阻止这个?
$(window).on("popstate", function() {
if ($('body').hasClass('info')) {
$('body').removeClass("info").addClass("work");
$('.info_overlay').fadeOut(duration);
alert('popstate');
} else if ($('body').hasClass('work')) {
$('body').removeClass("work").addClass("info");
$('.info_overlay').fadeIn(duration);
} else {
$('body').removeClass("project").addClass("work");
$('.project_overlay').fadeOut(duration);
}
});
Run Code Online (Sandbox Code Playgroud) 为了提高我网站的性能/响应能力,我使用AJAX,replaceState,pushState和popstate监听器实现了部分页面加载.
我基本上将页面的中心部分(HTML)存储为历史记录中的状态对象.单击链接时,我只从服务器请求页面的中心位(用不同的Accept标识标识这些请求)并用javascript替换它.在popstate上,我抓住前面的中央部分并将其推回到dom中.
这大部分工作正常,但我发现了一个我坚持的特殊问题.解释起来有点复杂,所以如果不是很清楚我会道歉.
我们的大部分页面都有一个搜索表单.通过ajax加载部分页面仅在GET请求上,并且表单执行POST,导致整页加载.
如果我浏览下面的一组页面,我最终会出现一个格式错误的部分页面,其中只包含中心内容,而不包含任何周围的dom:
从主页开始(通过整页加载) - 执行搜索(重定向后)
获取搜索结果(通过整页加载) - 然后单击主页
返回主页(通过动态获取) - 单击浏览器返回
搜索结果(来自popstate listener) - 单击浏览器返回
格式错误的主页.
当出现格式错误的主页时,我的popstate监听器根本不存在.
我认为正在发生的是,主页的第二次加载(动态,部分)被浏览器缓存,然后当整页回复发生时,浏览器只显示缓存的部分响应而不是整页.
为了解决这个问题,我在响应中添加了一个Vary:Accept标头,让浏览器知道内容可能会根据accept标头发生变化.我还为部分加载的内容添加了Cache-Control max-age = 0,pragma no-cache和过去的到期日期,以试图强制浏览器不缓存它,但这些都没有解决它.
不幸的是我的公司不允许我们的开发服务器的外部流量,所以我不能告诉你这个问题.我在这里看过各种类似的问题,但它们似乎都不一样,所提出的解决方案似乎也没有用.
如果我向动态GET请求添加一个无意义的参数(blah = blah),这就解决了这个问题.然而,这是一个丑陋的黑客,我宁愿不做.这似乎应该可以解决标题,因为我认为这是一个缓存问题.谁能解释一下发生了什么?
在iOS 7 Safari中,现在有两种向后/向前导航的方式 - 使用底部的传统后退/前进按钮箭头或从屏幕边缘滑动.我正在使用动画在我的ajax应用程序中的页面之间进行转换,但如果用户通过边缘滑动导航,我不想触发该转换,因为这是一个动画本身.
但是,对于这两种类型的导航,popstate事件对象看起来都是相同的 - 有没有办法区分这两种类型的用户导航,以便我们可以做出相应的响应?
更新:我能够使用(似乎是)iOS7 Safari中的错误来正确检测边缘滑动与后退按钮点击.问题在于,当使用边缘滑动(但是touchstart和touchmove)时,触摸事件不会被触发(直到下一个触摸事件).所以我设置了一个shouldAnimate标志并在touchmove上禁用它 - 然后如果标志被禁用并且popstate发生,我知道这是一个边缘滑动.
它在99%的时间是正确的 - 唯一可能失败的时间是用户边缘部分滑动但然后放开并让当前页面快速恢复到位(此时我的标志仍将被禁用)然后点击后退按钮(不触发任何触摸事件).为了处理最后的[边缘]情况,我在touchmove上设置了一个定时器,以便在50ms后重新启用该标志.
是的它是"脏"但是现在几乎在每种情况下它都能得到我想要的东西所以我很好 - 直到Apple修复了这个bug,但希望它们也能在popstate事件对象中提供一个告诉我们的指示器它是什么样的导航.
是否有可能将最后一个状态的html推送到历史堆栈,如下所示:
history.pushState(null, null, {html: $('body').html()});
Run Code Online (Sandbox Code Playgroud)
更改窗口位置:
window.location = url;
Run Code Online (Sandbox Code Playgroud)
现在从新的位置:
window.addEventListener('popstate', function(event) {
// back to the last state - event.state.html
}
history.back() // That what's firing the popstate event?
Run Code Online (Sandbox Code Playgroud) 这是一个简单的例子pushState和popstate事件:
<button id="example_btn">Click me</button>
<script>
$("#example_btn").click(function(){
history.pushState(
{
'url' : "example.htm"
}, null, "example.htm");
});
$(window).bind('popstate', function (event) {
if (event.originalEvent.state) {
console.log(event.originalEvent.state.url);
}
});
</script>
Run Code Online (Sandbox Code Playgroud)
触发popstate事件时,它会显示当前页面的URL.
我的问题是:
在这种情况下,如何在触发事件时获取上一页的网址popstate?
PS我试过document.referrer但它没有显示任何东西.
我正在尝试使用填充当前所选选项卡的索引
history.pushState({tabSelected: 1}, null, "");
Run Code Online (Sandbox Code Playgroud)
我有一个jquery中popstate事件的处理程序,它以编程方式切换jquery ui选项卡.
$(window).bind("popstate", function(event) {
var state = event.originalEvent.state;
...
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,浏览器和我可以使用后退和前进按钮在选项卡之间切换.也适用于两层标签.
但在某些情况下,我想将其他状态推送到堆栈.所以我做了以下事情:
var content = { targetId : id,
targetContent : $("#myDivId").html()
};
$.extend(content, {tabSelected: currentTab});
history.pushState(content, null, "");
Run Code Online (Sandbox Code Playgroud)
我把它推到历史之前和之后看起来都很好.检查console.log(history.state); 还尝试检查chrome控制台.
但是在我的popstate处理程序中,我没有在对象event.originalEvent.state上看到targetId,tabSelected属性.我在对象上看到tabSelected的正确值,但由于某种原因,我看到了一个削减状态.
检查Chrome和Firefox.无法获得正确的内容.什么想法可能是错的?提前致谢.
更新
还尝试在每个pushstate上递增一个全局变量并将其添加到状态.事实证明,对于特定情况,我提到全局变量变为值48而不是49意味着它正在拾取最后一个事件.我没有看到我的popstate处理程序被调用.不知道发生了什么.
另一个更新
当我调用history.pushState(content,null,"")两次时它可以正常工作.(只在一个地方,在另一个地方,我仍然称它为一次).看起来由于某种原因,浏览器返回的是最后一个状态.显然我的代码有问题,因为这个解决方法适用于chrome和firefox.
有什么办法可以在window.popstate被解雇时获得新页面的网址吗?
window.onpopstate(function (){
newPageUrl = //get the new page's URL
})
Run Code Online (Sandbox Code Playgroud) popstate ×10
javascript ×6
jquery ×5
pushstate ×4
html5 ×2
pjax ×2
ajax ×1
back-button ×1
getscript ×1
history ×1
http-headers ×1
ios ×1
safari ×1
webkit ×1