问题
Quick backstory:
I had everything working perfectly, but after some time, I noticed it no longer functioned properly. The ability to go back a "page" is extremely important to me, so I set about undoing any recent changes I'd made. That didn't work, so I decided to recreate the framework (hoping to piece in the content to find the trouble spot), yet still the problem persists. I've distilled the code down to the basics below.
I used to be able to hit the back button, and I would be immediately taken to the previous panel. NOW, nothing happens except that the "#page_name" is changed and the current panel shifts 1px. If I've clicked a few links (thereby storing more of a history "trail"), then once I hit the back button a second time, I finally go back a state, but not to the right one.
Here's a fiddle: http://jsfiddle.net/gz9nW/
JQ
$(document).ready(function(){
$('.main-nav').on('click',function (e) {
e.preventDefault();
var target = $(this).attr("href");
$target = $(target);
$('html, body').stop().animate({
'scrollLeft': $target.offset().left,
'scrollTop': $target.offset().top
}, 900, 'swing', function () {
window.location.hash = target;
});
});
});
CSS
html {
font: 100% 'PT Sans', sans-serif;
height:100%;
width:100%;
margin:0%;
padding:0%;
}
body {
font-size:1.25em;
width:100%;
margin:0%;
padding:0%;
overflow:hidden;
}
header {
width:100%;
position:fixed;
z-index:5000;
top:0%;
left:0%;
padding:0%;
margin:0%;
background:silver;
}
/*################################ NAV ################################*/
nav ul {
list-style:none;
}
nav ul li {
display:inline;
margin-right:5px;
}
/*################################ WRAPPER ################################*/
.wrapper {
width:1000%; /* #PAGES X 100% */
height:100%;
}
/*################################ PAGES ################################*/
.page-container {
width:10%; /* 1 / #PAGES */
display:inline-block;
vertical-align:top;
padding:0%;
margin:0%;
margin-right:-5px;
}
.page-container:nth-child(even) {
background:lightgreen;
}
.page-container:nth-child(odd) {
background:lightblue;
}
.page-contents {
padding:10% 0%;
width:61%;
margin-left:auto;
margin-right:auto;
background:grey;
}
HTML
<body>
<header>
<nav>
<ul>
<li><a class="main-nav" href="#home">Home</a></li>
<li><a class="main-nav" href="#products">Products</a></li>
<li><a class="main-nav" href="#services">Services</a></li>
<li><a class="main-nav" href="#quote">Quote</a></li>
<li><a class="main-nav" href="#about">About</a></li>
<li><a class="main-nav" href="#contact">Contact</a></li>
</ul>
</nav>
</header>
<div class="wrapper">
<div class="page-container" id="home">
<div class="page-contents">
home
</div>
</div>
<div class="page-container" id="products">
<div class="page-contents">
products
</div>
</div>
<div class="page-container" id="part-list">
<div class="page-contents">
part list catalog
</div>
</div>
<div class="page-container" id="services">
<div class="page-contents">
services
</div>
</div>
<div class="page-container" id="quote">
<div class="page-contents">
quote request
</div>
</div>
<div class="page-container" id="about">
<div class="page-contents">
about
</div>
</div>
<div class="page-container" id="contact">
<div class="page-contents">
contact page
</div>
</div>
<div class="page-container" id="inquiries">
<div class="page-contents">
solution inquiries
</div>
</div>
<div class="page-container" id="news">
<div class="page-contents">
news
</div>
</div>
<div class="page-container" id="legal">
<div class="page-contents">
legal info
</div>
</div>
</div>
</body>
It's a huge blow to this project, as this specific functionality was something I was after. Any help would be greatly appreciated!
回答1:
This should fix your issue:
DEMO
$(document).ready(function () {
$('.main-nav').on('click', function (e) {
e.preventDefault();
var toTarget = $(this).attr('href');
history.pushState(null, null, toTarget);
$(window).triggerHandler('hashchange');
});
});
$(window).on('hashchange', function () {
if(!window.location.hash) return;
var $target = $(window.location.hash);
$('html, body').stop().animate({
scrollLeft: $target.offset().left,
scrollTop: $target.offset().top
}, 900, 'swing');
});
回答2:
I wanted to add this so that those who have trouble with cross-browser compliance when using Wolff's code can have some reprieve from banging their head against [...dealer's choice].
Back to Home Issue
Some browsers don't play nice when trying to go back to the home page, as it has no hashvalue.
Home Page Hash Fix
function hashHome() {
var currentHash = location.hash;
var homeHash = '#home';
if (currentHash == '') {
history.pushState(null, null, homeHash);
}
}
hashHome();
Webkit Simultaneous Scrolling Issue
A HUGE problem in some webkit browsers, specifically mobile (read iOS!!!), is that when you simultaneously scroll horizontally and vertically, what you end up with is a sputtering, jittery mess that lands you back where you started. Quite devastating, and very perplexing.
I initially thought this was due to the browser not hashing the new values, but I later realized that the new values were there, just not "reported" to the viewport. The iOS address bar (7+) doesn't reveal changes as they happen, only after tapping the address bar (DOI! whoops, should've tried that first thing...) did I figure it out. Call me crazy, but if your code relies on one thing (the new hashvalue), and that thing isn't visibly happening, you might assume (like I did) that the reason the code isn't working is because of the one thing you're "seeing" isn't happening.
For complete explanation: Horizontal One-Page Site: Mobile-Webkit Scrolling & Swiping Issues
The click function remains the same as Wolff's.
Cross-browser Fix
$(window).on('hashchange', function() {
if(!window.location.hash) return;
var target = $(window.location.hash);
var targetHash = window.location.hash;
var iOS = ( navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? true : false );
var currentPosition = $(window).scrollLeft();
var targetPosLeft = target.offset().left;
var targetPosTop = target.offset().top;
function unbindWindow() { $(window).unbind('scroll'); }
function repositionWin() {
unbindWindow();
$(window).on('scroll', function() {
var alteredPosLeft = $(window).scrollLeft();
var alteredPosTop = $(window).scrollTop();
if (alteredPosLeft != targetPosLeft) {
window.scrollTo(targetPosLeft, alteredPosTop),
unbindWindow(),
repositionWin();
}
});
}
function fadePages() {
if (targetPosLeft == currentPosition) {
}
else {
function fadePageOut() {
$('.page-container').stop(true,false).animate({
opacity: "0.25",
transition: "opacity 0.1s 0.0s ease"
});
}
function fadePageIn() {
$('.page-container').stop(true,false).animate({
opacity: "1.0",
transition: "opacity 0.3s 0.0s ease"
});
}
fadePageOut();
setTimeout (fadePageIn, 900);
}
}
function pageChange() {
if (jQuery.browser.mobile === true) {
if (iOS === true) {
unbindWindow();
$('html,body').stop(true,false).animate({
scrollLeft: targetPosLeft}, 1400);
setTimeout (repositionWin, 1500);
}
else {
unbindWindow();
$('html,body').stop(true,false).animate({
scrollLeft: targetPosLeft}, 1200, function() {
$(this).stop(true,false).animate({
scrollTop: targetPosTop
}, 200, repositionWin);
});
}
}
else {
fadePages();
unbindWindow();
$('html,body').stop(true,false).delay(100).animate({
scrollLeft: targetPosLeft,
scrollTop: targetPosTop
}, 1300, repositionWin);
}
}
if ($('#mini-site-menu-button-container').is(':visible') === true && $('#main-menu-wrapper').hasClass('show-main-menu') === true) {
setTimeout (pageChange, 300)
}
if ($('.footer-container').is(':visible') === true) {
setTimeout (pageChange, 500)
}
if ($('.form-instructions-wrapper').hasClass('expand-form-instruct') === true) {
setTimeout (pageChange, 500)
}
if ($('.quick-quote-container').hasClass('toggle-open') === true) {
setTimeout (pageChange, 500)
}
if ($('#mini-site-menu-button-container').is(':visible') === false && $('.footer-container').is(':visible') === false && $('.form-instructions-wrapper').hasClass('expand-form-instruct') === false && $('.quick-quote-container').hasClass('toggle-open') === false) {
pageChange();
}
if ($('#main-menu-wrapper').hasClass('show-main-menu') === false && $('.footer-container').is(':visible') === false && $('.form-instructions-wrapper').hasClass('expand-form-instruct') === false && $('.quick-quote-container').hasClass('toggle-open') === false) {
pageChange();
}
});
Additional Notes
I removed most of my additional code, but left the conditional statements on end to show how you might call the page change on a mobile site. Depending on how you choose to allow the user to navigate your page (I chose to pop my menu out from the left, hence the "toggle-open"), you'll want to allow your other animations time to complete before you fire the scrolling animation. It tends to be a lot for most mobile devices to handle all at once. I'm still too green to understand how animations que, so this is how I addressed it.
I also added a function to fade the page container while it's scrolling. If you're going from one end of the site to the other, there's quite a bit of leg work involved in traveling that far. That much content whizzing by can be a bit off-putting to watch. Fading it a little seems to dull the blow, and I daresay it adds a little something, as well.
Lastly, for touch enabled devices, I added a function that monitors and corrects the horizontal scroll position in between page changes. It's really easy to accidentally scroll left and right by swiping on a phone, so it seemed necessary.
来源:https://stackoverflow.com/questions/21993231/horizontal-one-page-site-wont-go-backwards-to-previous-div