When is the scroll event fired when a page is loading? - javascript

If I go to a page with a hash tag, e.g http://www.wired.com/#spack4, I notice that the page loads and then jumps down to the id spack4. I'd like to attach a Javascript function for when it jumps down. Is there a DOM event that triggers this?

What are you trying to do?
Maybe you could use the window.pageYoffset property to check if the document is or is not at the top:
function isTopOfPage() {
var yPosition = window.pageYOffset;
if(yPosition == 0) {
//top of page
return true;
}
else if(yPosition > 0) {
// not at the top of the page
return false;
}
}
You can then call this function onload.

Related

Restore scroll position after mobile menu is closed

I'm having a mobile menu that opens and closes using jquery by adding a css class that has display:block while the menu div has display:none.
The jquery code has a part where it is supposed to close the menu when a click is registered outside the menu div. Everything works execept the: $("body").scrollTop(scrollpos) . This was supposed to scroll the user back where he left off after the scrollTop(0) took place and the menu has closed, but it does not scroll at all the scroll is stuck at the top. Any help will be appreciated. Thank you.
EDIT: Here is an example: https://jsfiddle.net/mufwwudj/
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
menutoggle.click(function () {
var scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
});
One problem here is that you are assigning a new mouseup event every time the menutoggle.click function runs.
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
Only the first one passes the conditional, even though each one will fire and scrollpos will always equal whatever it was in the first mouseup event listener.
I don't know how you are testing it, or what the HTML looks like but if you are at the top of the page the first time you click it, scrollpos in the mouseup event will always be 0.
Try assigning the mouseup event once, and putting scrollpos outside both so it can be accessed in both.
$(function () {
var menutoggle = $(".menu-toggle");
var sidenav = $(".side-nav");
var scrollpos;
menutoggle.click(function () {
scrollpos = $('body').scrollTop();
if (!$("body").hasClass("m-nav-open")) {
$("body").scrollTop(0).addClass("m-nav-open");
}
});
$(document).mouseup(function (e){
if (!sidenav.is(e.target) && sidenav.has(e.target).length === 0 && !menutoggle.is(e.target) && menutoggle.has(e.target).length === 0){
if ($("body").hasClass("m-nav-open")) {
$("body").scrollTop(scrollpos).removeClass("m-nav-open");
}
}
});
});
function ScrollOnTopo() {
window.scrollTo(0, 0); //It scrolls page at top
}
This function may be useful to you.

How to prevent duplicate events when scroll in jQuery?

I have 4 divs like;
<div class="diva">diva</div>
<div class="divb">divb</div>
<div class="divc">divc</div>
<div class="divd">divd</div>
They are 400px wide and high. I want to alert a when div b scrolls to top of page, and did using scroll function and scrollTop method. Each time when scroll, it check if scrollTop() if lager than 400, and alert a. But if I don't click the on the ok button of alert window, if I continue scrolling, multiple alerts will come, and I have to close them all.
But I just want one alert, and even if I continue scrolling, I want no more alerts. Also if the scrollTop is below 400px, I want to alert b (here also, I don't want repeats). If I got alert a, and if I scroll in opposite direction, and if scrollTop becomes below 400px, I want alert b, no problem for that.
Here is the fiddle.
please add this script on your file JS and try this script:
$(document).ready(function() {
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > jQuery(".divb").height()){
alert("a");
}else{
alert("b");
}
});
});
You are popping alerts on a 'scroll' event which happens every time you scroll..
if this is just a debugging annoyance, what you can do is use console.log('a') instead - example
If you wanted the actual function to run once for each time you reach it you can do this:
var a = false;
$(window).scroll(function(){
var xx = $(document).scrollTop();
if(xx > 400){
if (!a) {
alert("a");
a = true;
}
}else{
if (a) {
alert("b");
a = false;
}
}
});
fiddle for this example
The easiest way to avoid any confusion would be to keep state of scroll actions.
Demo: http://jsfiddle.net/abhitalks/uwUvC/1/
var last = 0, // last scroll-top to determine scroll direction
scrolledUp = false, // to cache state of scroll up
scrolledDown = false; // to cache state of scroll down
$(window).scroll(function (event) {
var current = $(this).scrollTop();
if (current > last) { // if scrolled down
if (current > 400 && !scrolledDown) { // check position and state
alert("A");
scrolledDown = true; // reset scroll down state
}
} else { // if scrolled up
if (current < 400 && scrolledDown && !scrolledUp) {
alert("B");
scrolledUp = true; // reset scroll up state
}
}
last = current; // keep current position to check direction
});
This way you are sure about when you are scrolling up and when you are scrolling down. Keep state of scroll in respective variables and check them.
The alerts fire only once in each direction.

How can I launch a JavaScript or jQuery event when I reach the top of my page?

I have a simple problem, but I can't find the solution ...
I just want to launch an event (which execute a method) when I scroll my page up and I "touch" the top of it. I'm using JavaScript and jQuery in my page. Thanks in advance !
You should use the scroll event for that purpose:
$(window).scroll(function() {
if ($(this).scrollTop() == 0) {
//Do whatever you want to do
}
});
One thing you should notice is that this way when somebody scrolls to top continuously the even will be fired although you only want it once the top is hit, for this you can define the event handler as a function and put the last scrolltop value into a function local variable.
$(window).scroll(handleHitTop);
function handleHitTop(event) {
var currentScrollTopValue = $(this).scrollTop();
if (handleHitTop.lastTop === undefined) {
handleHitTop.lastTop = currentScrollTopValue ;
return;
}
if (handleHitTop.lastTop == 0 && currentScrollTopValue == 0) {
return;
}
handleHitTop.lastTop = currentScrollTopValue;
if (handleHitTop.lastTop == 0) {
//Call your event here
}
}
Use the onscroll event. Vanilla js example:
window.onscroll = function() {
if(document.body.scrollTop == 0) {
alert('yay!');
}
}
http://jsfiddle.net/kuWuf/
Use a .scroll() handler and .scrollTop():
$(window).scroll( function() {
if($(this).scrollTop() == 0) {
alert("Top!!!");
}
});
http://jsfiddle.net/jtbowden/wvJ9r/

Smooth Scrolling Interferes with Hash Mark

EDIT (12/26/2012)
I found the following code which does exactly what I want, except now when a page's URL has a trailing slash (e.g. example.com/page/), the page doesn't scroll. Works fine if the page's URL ends with '.php' or '.html', etc. Any thoughts on how to get the following script to work with the trailing slash in a URL?
jQuery('a[href*=#]').bind('click', function(e) {
// Get the target
var target = jQuery(this).attr("href");
// prevent the "normal" behaviour which would be a "hard" jump
e.preventDefault();
// perform animated scrolling by getting top-position of target-
// element and set it as scroll target
jQuery('html, body').stop().animate({
scrollTop: jQuery(target).offset().top
}, 500, function() {
location.hash = target; //attach the hash (#jumptarget) to the pageurl
});
return false;
});
I've been using a script successfully for the last couple of years, but have recently run into some issues with it. Basically what the script does is scroll the page to a specific point. This happens with link anchors. For example, if one link is:
anchor link
The page will smoothly scroll to that anchor on the page:
<a name="anchor"></a>
Or:
<a id="anchor"></a>
The issue that occurs arises when some other JS is being used in the page which requires a link to be formatted as such:
other link
When this "other link" is clicked, the page will smoothly scroll, BUT to the top or bottom of the page where there is NO anchor.
What should happen when this "other link" is clicked? The other JS action should occur (which it does), but the smooth page scrolling script should not occur.
Here's a working example from where I got this script:
http://www.dezinerfolio.com/wp-content/uploads/smoothscrolldemo/df_smooth_scroll.html
Here's the JS in full:
Scroller = {
// control the speed of the scroller.
// dont change it here directly, please use Scroller.speed=50;
speed: 10,
// returns the Y position of the div
gy: function (d) {
gy = d.offsetTop
if (d.offsetParent) while (d = d.offsetParent) gy += d.offsetTop
return gy
},
// returns the current scroll position
scrollTop: function (){
body = document.body
d = document.documentElement
if (body && body.scrollTop) return body.scrollTop
if (d && d.scrollTop) return d.scrollTop
if (window.pageYOffset) return window.pageYOffset
return 0
},
// attach an event for an element
// (element, type, function)
add: function(event, body, d) {
if (event.addEventListener) return event.addEventListener(body, d,false)
if (event.attachEvent) return event.attachEvent('on'+body, d)
},
// kill an event of an element
end: function(e){
if (window.event) {
window.event.cancelBubble = true
window.event.returnValue = false
return;
}
if (e.preventDefault && e.stopPropagation) {
e.preventDefault()
e.stopPropagation()
}
},
// move the scroll bar to the particular div.
scroll: function(d){
i = window.innerHeight || document.documentElement.clientHeight;
h = document.body.scrollHeight;
a = Scroller.scrollTop()
if (d>a)
if(h-d>i)
a += Math.ceil((d-a)/Scroller.speed)
else
a += Math.ceil((d-a-(h-d))/Scroller.speed)
else
a = a + (d-a)/Scroller.speed;
window.scrollTo(0,a)
if (a==d || Scroller.offsetTop==a)
clearInterval(Scroller.interval)
Scroller.offsetTop = a
},
// initializer that adds the renderer to the onload function of the window
init: function(){
Scroller.add(window,'load', Scroller.render)
},
// this method extracts all the anchors and validates then as # and attaches the events.
render: function(){
a = document.getElementsByTagName('a');
Scroller.end(this);
window.onscroll
for (i=0;i<a.length;i++) {
l = a[i];
if (l.href && l.href.indexOf('#') != -1 && ((l.pathname==location.pathname) || ('/'+l.pathname==location.pathname)) ){
Scroller.add(l,'click',Scroller.end)
l.onclick = function(){
Scroller.end(this);
l = this.hash.substr(1);
a = document.getElementsByTagName('a');
for (i=0;i<a.length;i++) {
if (a[i].name == l){
clearInterval(Scroller.interval);
Scroller.interval = setInterval('Scroller.scroll('+Scroller.gy(a[i])+')',10);
}
}
}
}
}
}
}
// invoke the initializer of the scroller
Scroller.init();
I would think that there is a way to write the script so that if the href is equal to just the hash mark # without any text after the hash, that the scroller wouldn't be triggered.
Does anyone have any better ideas?
Thanks in advance!
I can't help you with your jQuery function, but there are two simple solutions to your original script. The first is a small modification to tell the script to ignore the special case where an anchor's URL is only the hash tag.
In the render function, change the line:
if (l.href
&& l.href.indexOf('#') != -1
&& (l.pathname == location.pathname
|| '/' + l.pathname == location.pathname)
) {
To:
if (l.href
&& l.href != '#' // <<< Added this conditional >>>
&& l.href.indexOf('#') != -1
&& (l.pathname == location.pathname
|| '/' + l.pathname == location.pathname)
){
This will tell the script to ignore the special case, but won't prevent the browser from reacting normally to the link, so the browser may still jump to the top of the page. The special case you've mentioned is almost always used in javascript constructions to provide an anchor tag with an href attribute, because some older browsers would ignore the tag without one. The '#' was used as the URL to prevent the link from leaving the page.
Instead of the '#', you could use an empty javascript call in your link, like so:
other link
This will avoid your issues with the scrollers completely.
Thanks again, Jarred, for your help! I did come across a script that does just what I want. Here's the better script I found:
jQuery('a[href*=#]').bind('click', function(e) {
e.preventDefault(); //prevent the "normal" behaviour which would be a "hard" jump
var target = jQuery(this).attr("href"); //Get the target
// perform animated scrolling by getting top-position of target-element and set it as scroll target
jQuery('html, body').stop().animate({ scrollTop: jQuery(target).offset().top }, 1000, function() {
location.hash = target; //attach the hash (#jumptarget) to the pageurl
});
return false;
});

jquery click event doesn't always fire after browser has been resized

I've got a fairly simple navigation menu that opens and closes on click. The menu behaviour only comes into play when the browser viewport is below a certain size.
It all works great 90% of the time. The remaining 10% of the time (when I'm demonstrating it to the client, natch) the click event doesn't fire at all. As far as I can tell, the problem only occurs after the browser has been resized a few times, but as it usually works normally when the window has been resized, it's difficult to track down why it's happening.
Code:
var smallViewport = false;
$(document).ready(function(){
if($(window).width() < 520) {
smallViewport = true;
}
if(smallViewport == true) {
$('nav.main').click(function(){
console.log(' + clicky clicky');
if($(this).find('.level-1').hasClass('open') == true) {
$(this).find('.level-1').slideUp('fast').removeClass('open');
} else {
$(this).find('.level-1').slideDown('fast', function(){ $(this).addClass('open'); });
}
})
}
});
$(window).resize(function() {
if($(window).width() < 520) {
smallViewport = true;
} else {
smallViewport = false;
}
console.log(smallViewport);
if(smallViewport == true) {
$('.level-1').removeClass('open').css('display','none');
} else {
$('.level-1').css('display','block');
}
});
When the problem chooses to manifest itself, console.log(smallViewport) in the resize function outputs 'true' when it should be true, the click event just refuses to fire along with it.
Has anybody encountered a similar problem before? Any obvious solutions I'm missing?
You're only binding the click when the page loads, not when it's resized
if $(window).width() < 520 evaluates as false on the page load, the click event will not be bound - which is why your console log is correct but the event is not firing
Put the viewport check inside the click event handler. As it is now, the event handler isn't bound if the check evaluates to false on page load. Try changing it to this:
$('nav.main').click(function(){
if(smallViewport == true) {
console.log(' + clicky clicky');
if($(this).find('.level-1').hasClass('open') == true) {
$(this).find('.level-1').slideUp('fast').removeClass('open');
} else {
$(this).find('.level-1').slideDown('fast', function() {
$(this).addClass('open');
});
}
}
}​);​

Categories