I'm trying to get the event for a mousewheel scroll right before it happens so that I can stop the scroll and do some stuff and then give back control to the user.
Currently I have the following code to cancel out the scroll. However the scroll happens once and then control is taken away from the user. I'd like to make sure the scroll does not happen, do some other stuff instead, and then give control back afterwards.
$('body').on({ 'mousewheel': function(e) {
e.preventDefault();
e.stopPropagation();
}});
How can I do this?
You can use the onwheel event.
window.onwheel = function(){
alert('your magic here');
return false;
}
Are you able to debug and see if the event is being fired in the first scroll?
Is your code inside a $(document).ready( function?
If you are using jquery-mousewheel plug-in, you will be able to call this only if you are attaching it after the plug-in is ready and declared before your script (might be on your page header).
When linking to a page using a named anchor e.g. page.html#heading the browser will load the page, then jump down to the anchor. Is there a browser event that fires when this has completed?
To explain my reasons behind it: I want to use the event to trigger an animation in the browser.
Many thanks.
Changing the hash triggers the hashchange event.
However, I don't think it fires when loading a url where the link already has the hash set. But you can check the hash (location.hash) on page load if you want a certain script to run depending on the hash.
In Safari 7.0.3 on the Mac this works...
HTML has:
<a id="jumper" href="#aa">Jump</a>
JS:
<script>
var j = document.getElementById("jumper");
j.addEventListener("click", registerAnchorJump);
function registerAnchorJump(e) {
window.addEventListener("scroll", unregisterAnchorJump);
}
function unregisterAnchorJump(e) {
// trigger your animation...
console.log(window.scrollY);
window.removeEventListener("scroll",unregisterAnchorJump);
}
</script>
Fancy footwork to prevent constant firing of scroll event as user scrolls window normally.
I'm using this script
jQuery(document).ready(function($) {
$(".scroll").click(function(event){
event.preventDefault();
$('html,body').animate({scrollTop:$(this.hash).offset().top}, 2000);
});
});
in order to smooth scroll down when my nav elements are clicked... the problem is that if a link is clicked before page finish loading, when it finishes the page will go back to top again.
I thought event.preventDefault(); was to avoid that. Help please.
you should use the document.onLoad event instead.
document.ready is invoked after all of the HTML is brought down into the document and ready for parsing.
onLoad on the other hand is invoked after all images / resources are loaded into the page as well.
If you wait for this event, then you should have desired results. although they won't have any click functionality until then.
Furthermore, preventDefault does not avoid this. All that does is disable the default action of the element you apply it to. so it prevent's whatever the default action would be for your 'scroll' elements
Is it possible to prevent the default behaviour of scrolling the document when a popstate event occurs?
Our site uses jQuery animated scrolling and History.js, and state changes should scroll the user around to different areas of the page whether via pushstate or popstate. The trouble is the browser restores the scroll position of the previous state automatically when a popstate event occurs.
I've tried using a container element set to 100% width and height of the document and scrolling the content inside that container. The problem with that I've found is it doesn't seem to be nearly as smooth as scrolling the document; especially if using lots of css3 like box-shadows and gradients.
I've also tried storing the document's scroll position during a user initiated scroll and restoring it after the browser scrolls the page (on popstate). This works fine in Firefox 12 but in Chrome 19 there is a flicker due to the page being scrolled and restored. I assume this is to do with a delay between the scroll and the scroll event being fired (where the scroll position is restored).
Firefox scrolls the page (and fires the scroll event) before popstate fires and Chrome fires popstate first then scrolls the document.
All the sites I've seen that use the history API either use a solution similar to those above or just ignore the scroll position change when a user goes back/forward (e.g. GitHub).
Is it possible to prevent the document being scrolled at all on popstate events?
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
(Announced by Google on September 2, 2015)
Browser support:
Chrome: supported (since 46)
Firefox: supported (since 46)
IE: not supported
Edge: supported (since 79)
Opera: supported (since 33)
Safari: supported
For more info, see Browser compatibility on MDN.
This has been a reported issue with the mozilla developer core for more than a year now. Unfortunately, the ticket did not really progress. I think Chrome is the same: There is no reliable way to tackle the scroll position onpopstate via js, since it's native browser behaviour.
There is hope for the future though, if you look at the HTML5 history spec, which explicitly wishes for the scroll position to be represented on the state object:
History objects represent their browsing context's session history as a flat list of session history entries. Each session history entry consists of a URL and optionally a state object, and may in addition have a title, a Document object, form data, a scroll position, and other information associated with it.
This, and if you read the comments on the mozilla ticket mentioned above, gives some indication that it is possible that in the near future scroll position will not be restored anymore onpopstate, at least for people using pushState.
Unfortunately, until then, the scroll position gets stored when pushState is used, and replaceState does not replace the scroll position. Otherwise, it would be fairly easy, and you could use replaceState to set the current Scroll position everytime the user has scrolled the page (with some cautious onscroll handler).
Also unfortunately, the HTML5 spec does not specify when exactly the popstate event has to be fired, it just says: «is fired in certain cases when navigating to a session history entry», which does not clearly say if it's before or after; if it was always before, a solution with handling the scroll event occuring after the popstate would be possible.
Cancel the scroll event?
Furthermore, it would also be easy, if the scroll event where cancelable, which it isn't. If it was, you could just cancel the first scroll event of a series (user scroll events are like lemmings, they come in dozens, whereas the scroll event fired by the history repositioning is a single one), and you would be fine.
There's no solution for now
As far as I see, the only thing I'd recommend for now is to wait for the HTML5 Spec to be fully implemented and to roll with the browser behaviour in this case, that means: animate the scrolling when the browser lets you do it, and let the browser reposition the page when there's a history event. The only thing you can influence position-wise is that you use pushState when the page is positioned in a good way to go back to. Any other solution is either bound to have bugs, or to be too browser-specific, or both.
You're going to have to use some kind of horrible browser sniffing here. For Firefox, I would go with your solution of storing the scroll position and restoring it.
I thought I had a good Webkit solution based on your description, but I just tried in Chrome 21, and it seems that Chrome scrolls first, then fires the popstate event, then fires the scroll event. But for reference, here's what I came up with:
function noScrollOnce(event) {
event.preventDefault();
document.removeEventListener('scroll', noScrollOnce);
}
window.onpopstate = function () {
document.addEventListener('scroll', noScrollOnce);
};
Black magic such as pretending the page is scrolling by moving an absolute positioned element is ruled out by the screen repainting speed too.
So I'm 99% sure that the answer is that you can't, and you're going to have to use one of the compromises you've mentioned in the question. Both browsers scroll before JavaScript knows anything about it, so JavaScript can only react after the event. The only difference is that Firefox doesn't paint the screen until after the Javascript has fired, which is why there's a workable solution in Firefox but not in WebKit.
Now you can do
history.scrollRestoration = 'manual';
and this should prevent browser scroll. This only works right now in Chrome 46 and above, but it seems that Firefox is planning to support it too
The solution is to use position: fixed and specify top equal to scroll position of page.
Here is an example:
$(window).on('popstate', function()
{
$('.yourWrapAroundAllContent').css({
position: 'fixed',
top: -window.scrollY
});
requestAnimationFrame(function()
{
$('.yourWrapAroundAllContent').css({
position: 'static',
top: 0
});
});
});
Yes, you instead receive flickering scrollbar, but it is less evil.
The following fix should work in all browsers.
You can set scroll position to 0 on the unload event. You can read about this event here: https://developer.mozilla.org/en-US/docs/Web/Events/unload. Essentially, the unload event fires right before you leave the page.
By setting scrollPosition to 0 on unload means when you leave the page with a set pushState it sets scrollPosition to 0. When you return to this page by refreshing or pressing back it will not autoscroll.
//Listen for unload event. This is triggered when leaving the page.
//Reference: https://developer.mozilla.org/en-US/docs/Web/Events/unload
window.addEventListener('unload', function(e) {
//set scroll position to the top of the page.
window.scrollTo(0, 0);
});
Setting scrollRestoration to manual not worked for me, here is my solution.
window.addEventListener('popstate', function(e) {
var scrollTop = document.body.scrollTop;
window.addEventListener('scroll', function(e) {
document.body.scrollTop = scrollTop;
});
});
Create a 'span' element somewhere at the top of the page and set focus to this on load. The browser will scroll to the focussed element. I understand that this is a workaround and focus on 'span' doesn't work in all browsers ( uhmmm.. Safari ). Hope this helps.
Here is what I have implemented on a site that wanted the scroll position to focus to a specific element when the poststate is fired (back button):
$(document).ready(function () {
if (window.history.pushState) {
//if push supported - push current page onto stack:
window.history.pushState(null, document.title, document.location.href);
}
//add handler:
$(window).on('popstate', PopStateHandler);
}
//fires when the back button is pressed:
function PopStateHandler(e) {
emnt= $('#elementID');
window.scrollTo(0, emnt.position().top);
alert('scrolling to position');
}
Tested and works in firefox.
Chrome will scroll to position but then repositions back to original place.
Like others said, there is no real way to do it, only ugly hacky way. Removing the scroll event listener didn't work for me, so here's my ugly way to do it:
/// GLOBAL VARS ////////////////////////
var saveScrollPos = false;
var scrollPosSaved = window.pageYOffset;
////////////////////////////////////////
jQuery(document).ready(function($){
//// Go back with keyboard shortcuts ////
$(window).keydown(function(e){
var key = e.keyCode || e.charCode;
if((e.altKey && key == 37) || (e.altKey && key == 39) || key == 8)
saveScrollPos = false;
});
/////////////////////////////////////////
//// Go back with back button ////
$("html").bind("mouseout", function(){ saveScrollPos = false; });
//////////////////////////////////
$("html").bind("mousemove", function(){ saveScrollPos = true; });
$(window).scroll(function(){
if(saveScrollPos)
scrollPosSaved = window.pageYOffset;
else
window.scrollTo(0, scrollPosSaved);
});
});
It works in Chrome, FF and IE (it flashes the first time you go back in IE). Any improvement suggestions are welcome! Hope this helps.
Might want to try this?
window.onpopstate = function(event) {
return false;
};
I want to load more content when the user scrolls the webpage. I tried using
onScroll event javascript which is getting called multiple times
jQuery .scroll() method which is also called multiple times.
How do I handle this? Is it a browser issue?
Note: I am calling onScroll = "function()" on body tag of HTML.
On every scroll any scroll method would be called
So you should check when the user scrolls to the bottom, then load more content.
If you're getting a series of events as the window moves (similar to what happens on a resize event), then one trick is to set a timer for 1-2 seconds on the first scroll event, but not do anything yet. If a subsequent scroll event comes in before the timer fires, you stop the previous timer and set a new one. When the user stops scrolling for a brief time, the timer will fire and you can then process the scroll event. If they scroll some more, the whole process will repeat.
jQuery pseudo-code example:
var scrollTimer = null;
$("#target").scroll(function(){
if (scrollTimer) {
clearTimeout(scrollTimer); // clear previous timer
}
// set timer while we wait for a pause in scroll events
scrollTimer = setTimeout(function() {
scrollTimer = null; // timer done here
// do your dynamic loading here
}, 1000);
});
Load content while scrolling: http://www.webresourcesdepot.com/load-content-while-scrolling-with-jquery/