Hi I have one question about jquery window scroll function. I have code somthing like this.
$(window).scroll(function(){
if($(window).scrollTop() > $(".pages").offset().top) {
$('.top-slider').slick('slickPause');
}else {
$('.top-slider').slick('slickPlay');
}
});
Ok every time when you scroll if first is true it call every 1px scrolled window. Is that way to call just one time if true but check on scroll if other is true call that just one time?
Thanks for your answers :)
Try with a flag, something like this:
var paused = false;
$(window).scroll(function(){
if( $(window).scrollTop() > $(".pages").offset().top ) {
if( !paused ){
$('.top-slider').slick('slickPause');
paused = true;
}
}else {
if( paused ){
$('.top-slider').slick('slickPlay');
paused = false;
}
}
});
Adding a test variable will be a solution here :
var checkDown = true;
var checkUp = false;
$(window).scroll(function(){
if($(window).scrollTop() > $(".pages").offset().top && checkDown ) {
$('.top-slider').slick('slickPause');
checkDown = false;
checkUp = true;
}else if(checkUp) {
$('.top-slider').slick('slickPlay');
checkDown = true;
checkUp = false;
}
});
I tell you another solution, is a debouncer. Debounce functions make scroll and resize events more efficient, because stop the event firing till the end of the first fired event.
You can view a debounce function with underscore.js library.
http://underscorejs.org/#debounce
The use is simple:
var debounced = _.debounce(myFunction, 1000);
$(window).scroll(debounced);
Related
This is throwing me for a loop..
The basic idea is we're using $(window).scroll() and as you scroll down the page, when an element is in view by using offset() with scrollTop "do something" then when you hit the next element down the page "do something more".
However, because the scroll event (probably the wrong term) fires every single time in the conditional statement because technically the statement is true every scroll, I need it to only fire once, but then be able to 're-fire again' one time when the next conditional happens.
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
doSomething(); // want this to only fire once
} else if( windowTop > $('.element2').offset().top ) {
doSomething(); // want this to only fire once
}
});
I had a theory about possibly setting a variable to true so it only fire's doSomething() once, but then when it's inside the 2nd conditional statement I can't wrap my head around undoing / resetting it.
let fired = false;
$(window).scroll(function(){
let windowTop = $(window).scrollTop()
if( windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top ) {
if(!fired){
doSomething();
fired = true;
}
} else if( windowTop > $('.element2').offset().top ) {
// need to somehow set fired to false again so it triggers once then sets back to true
if(!fired){
doSomething();
fired = true;
}
}
});
Hope I somehow made sense!
Consider the following.
var fire = {
"element1": true,
"element2": true
};
$(window).scroll(function(event){
var windowTop = $(window).scrollTop();
console.log("Window Scroll Top: " + windowTop);
if( fire.element1 && (windowTop > $('.element').offset().top && windowTop < $('.element2').offset().top) ) {
console.log("Do Something!", $('.element').offset().top);
fire.element1 = false;
doSomething();
} else if( fire.element2 && (windowTop > $('.element2').offset().top) ) {
console.log("Do Something!", $('.element2').offset().top);
fire.element2 = false;
doSomething();
}
});
The logic here is we check if we should fire the event for each element. In this way we have a more complex IF condition. Fire for that element must be true and the Scroll position must have gone down far enough.
If the Top of the element is 100, this condition should only be true at one time and one time only, when windowTop is a value of 101 or higher. Now if you want it to trigger when the element is fully in view, you need the Top plus the Height. If it's 40px tall, then it would be 140 (Top + Height).
I want to call a function depending upon the direction of scroll i.e if we scroll down it call goDown() and if we scroll up then call goUp().
Here is my code :
$('.container').on('DOMMouseScroll mousewheel', function (e) {
if(e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
console.log('down');
goDown();
} else {
console.log('up');
goUp();
}
return false;
});
But if we scroll it is firing goDown() or goUp() multiple times which is not as I wanted, I just want to fire it once per scroll.
Use lodash's throttle.
In the example below, 1000 (1s) is the time which has to pass without any call to onScroll() before it can fire it again.
$('.container').on(
'DOMMouseScroll mousewheel',
_.throttle(
onScroll,
1000,
{trailing: false}
)
);
// your original function, named:
function onScroll (e) {
if(e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
console.log('scrolled down');
// goDown();
} else {
console.log('scrolled up');
// goUp();
}
return false;
}
.container {
height: 200vh;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container"></div>
If you want to fire onScroll() at the end of your wait period, not at start, use
{leading:false,trailing:true}
...as options (last param).
Also note there's a jQuery plugin for throttle and debounce but I never used it. What I know is that it has a slightly different syntax/approach to each (than _). Feel free to look into it if you don't want to load Lodash in your project.
you can make it with an timeout.
this is my oneliner
t=onscroll=e=>clearTimeout(t,t=setTimeout('console.log("finished")',500))
or with a few more lines:
var scrollWait,
scrollFinished = () => console.log('finished');
window.onscroll = () => {
clearTimeout(scrollWait);
scrollWait = setTimeout(scrollFinished,500);
}
This codes wait for 500ms an then fire finished.
You can translate this to your own situation.
I solved the problem in this way (please note that code should be optimized):
$(document).ready(function(){
var valid = true;
var power = 0; // <-- initial power
setInterval(function(){
if (power>0){
power=power/2; // <-- decrease power every 250ms
if (power<1) power=0;
console.log(power); // <-- you may remove this
}
},250);
$('.container').on('DOMMouseScroll mousewheel', function (e) {
e.preventDefault();
var c_power = Math.abs(e.originalEvent.wheelDeltaY)+Math.abs(e.originalEvent.wheelDeltaX); // <-- get current power
/* event is considered valid only if current power > power */
if (c_power>=power){
power=c_power;
valid=true;
}
if(valid && (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0)) {
console.log('down');
goDown();
} else {
console.log('up');
goUp();
}
return false;
});
});
Is there a way to get the mouse wheel events (not talking about scroll events) in jQuery?
$(document).ready(function(){
$('#foo').bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta /120 > 0) {
console.log('scrolling up !');
}
else{
console.log('scrolling down !');
}
});
});
Binding to both mousewheel and DOMMouseScroll ended up working really well for me:
$(window).bind('mousewheel DOMMouseScroll', function(event){
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
// scroll up
}
else {
// scroll down
}
});
This method is working in IE9+, Chrome 33, and Firefox 27.
Edit - Mar 2016
I decided to revisit this issue since it's been a while. The MDN page for the scroll event has a great way of retrieving the scroll position that makes use of requestAnimationFrame, which is highly preferable to my previous detection method. I modified their code to provide better compatibility in addition to scroll direction and position:
(function() {
var supportOffset = window.pageYOffset !== undefined,
lastKnownPos = 0,
ticking = false,
scrollDir,
currYPos;
function doSomething(scrollPos, scrollDir) {
// Your code goes here...
console.log('scroll pos: ' + scrollPos + ' | scroll dir: ' + scrollDir);
}
window.addEventListener('wheel', function(e) {
currYPos = supportOffset ? window.pageYOffset : document.body.scrollTop;
scrollDir = lastKnownPos > currYPos ? 'up' : 'down';
lastKnownPos = currYPos;
if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(lastKnownPos, scrollDir);
ticking = false;
});
}
ticking = true;
});
})();
See the Pen Vanilla JS Scroll Tracking by Jesse Dupuy (#blindside85) on CodePen.
This code is currently working in Chrome v50, Firefox v44, Safari v9, and IE9+
References:
https://developer.mozilla.org/en-US/docs/Web/Events/scroll
https://developer.mozilla.org/en-US/docs/Web/Events/wheel
As of now in 2017, you can just write
$(window).on('wheel', function(event){
// deltaY obviously records vertical scroll, deltaX and deltaZ exist too.
// this condition makes sure it's vertical scrolling that happened
if(event.originalEvent.deltaY !== 0){
if(event.originalEvent.deltaY < 0){
// wheeled up
}
else {
// wheeled down
}
}
});
Works with current Firefox 51, Chrome 56, IE9+
There's a plugin that detects up/down mouse wheel and velocity over a region.
Answers talking about "mousewheel" event are refering to a deprecated event. The standard event is simply "wheel". See https://developer.mozilla.org/en-US/docs/Web/Reference/Events/wheel
This worked for me:)
//Firefox
$('#elem').bind('DOMMouseScroll', function(e){
if(e.originalEvent.detail > 0) {
//scroll down
console.log('Down');
}else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
return false;
});
//IE, Opera, Safari
$('#elem').bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta < 0) {
//scroll down
console.log('Down');
}else {
//scroll up
console.log('Up');
}
//prevent page fom scrolling
return false;
});
from stackoverflow
Here is a vanilla solution. Can be used in jQuery if the event passed to the function is event.originalEvent which jQuery makes available as property of the jQuery event. Or if inside the callback function under we add before first line: event = event.originalEvent;.
This code normalizes the wheel speed/amount and is positive for what would be a forward scroll in a typical mouse, and negative in a backward mouse wheel movement.
Demo: http://jsfiddle.net/BXhzD/
var wheel = document.getElementById('wheel');
function report(ammout) {
wheel.innerHTML = 'wheel ammout: ' + ammout;
}
function callback(event) {
var normalized;
if (event.wheelDelta) {
normalized = (event.wheelDelta % 120 - 0) == -0 ? event.wheelDelta / 120 : event.wheelDelta / 12;
} else {
var rawAmmount = event.deltaY ? event.deltaY : event.detail;
normalized = -(rawAmmount % 3 ? rawAmmount * 10 : rawAmmount / 3);
}
report(normalized);
}
var event = 'onwheel' in document ? 'wheel' : 'onmousewheel' in document ? 'mousewheel' : 'DOMMouseScroll';
window.addEventListener(event, callback);
There is also a plugin for jQuery, which is more verbose in the code and some extra sugar: https://github.com/brandonaaron/jquery-mousewheel
This is working in each IE, Firefox and Chrome's latest versions.
$(document).ready(function(){
$('#whole').bind('DOMMouseScroll mousewheel', function(e){
if(e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0) {
alert("up");
}
else{
alert("down");
}
});
});
I was stuck in this issue today and found this code is working fine for me
$('#content').on('mousewheel', function(event) {
//console.log(event.deltaX, event.deltaY, event.deltaFactor);
if(event.deltaY > 0) {
console.log('scroll up');
} else {
console.log('scroll down');
}
});
use this code
knob.bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta < 0) {
moveKnob('down');
} else {
moveKnob('up');
}
return false;
});
The plugin that #DarinDimitrov posted, jquery-mousewheel, is broken with jQuery 3+. It would be more advisable to use jquery-wheel which works with jQuery 3+.
If you don't want to go the jQuery route, MDN highly cautions using the mousewheel event as it's nonstandard and unsupported in many places. It instead says that you should use the wheel event as you get much more specificity over exactly what the values you're getting mean. It's supported by most major browsers.
my combination looks like this. it fades out and fades in on each scroll down/up. otherwise you have to scroll up to the header, for fading the header in.
var header = $("#header");
$('#content-container').bind('mousewheel', function(e){
if(e.originalEvent.wheelDelta > 0) {
if (header.data('faded')) {
header.data('faded', 0).stop(true).fadeTo(800, 1);
}
}
else{
if (!header.data('faded')) header.data('faded', 1).stop(true).fadeTo(800, 0);
}
});
the above one is not optimized for touch/mobile, I think this one does it better for all mobile:
var iScrollPos = 0;
var header = $("#header");
$('#content-container').scroll(function () {
var iCurScrollPos = $(this).scrollTop();
if (iCurScrollPos > iScrollPos) {
if (!header.data('faded')) header.data('faded', 1).stop(true).fadeTo(800, 0);
} else {
//Scrolling Up
if (header.data('faded')) {
header.data('faded', 0).stop(true).fadeTo(800, 1);
}
}
iScrollPos = iCurScrollPos;
});
If using mentioned jquery mousewheel plugin, then what about to use the 2nd argument of event handler function - delta:
$('#my-element').on('mousewheel', function(event, delta) {
if(delta > 0) {
console.log('scroll up');
}
else {
console.log('scroll down');
}
});
I think many key things are a bit all over the place and I needed to read all the answers to make my code work as I wanted, so I will post my findings in just one place:
You should use "wheel" event over the other deprecated or browser specific events.
Many people here is getting something wrong: the opposite of x>0 is x<=0 and the opposite of x<0 is x>=0, many of the answers in here will trigger scrolling down or up incorrectly when x=0 (horizontal scrolling).
Someone was asking how to put sensitivity on it, for this you can use setTimeout() with like 50 ms of delay that changes some helper flag isWaiting=false and you protect yourself with if(isWaiting) then don't do anything. When it fires you manually change isWaiting=true and just below this line you start the setTimeout again who will later change isWaiting=false after 50 ms.
I got same problem recently where
$(window).mousewheel was returning undefined
What I did was $(window).on('mousewheel', function() {});
Further to process it I am using:
function (event) {
var direction = null,
key;
if (event.type === 'mousewheel') {
if (yourFunctionForGetMouseWheelDirection(event) > 0) {
direction = 'up';
} else {
direction = 'down';
}
}
}
I'm trying to prevent a link click from firing if accidentally touched while scrolling in mobile? I have never tried something like this before and am having trouble getting it to work right. I am testing this on a desktop for the time being.
My buttons are structured similar to:
<a href="http://www.google.com">
<div style="width:100%;height:80px;margin-bottom:50px;">test</div>
</a>
I am trying to use the preventDefault() function to override default click actions and check if a the page is being scrolled, or it the click was accidental before allowing it to work. The logic to check seems to work, however the links navigate on click no matter what i do. I assume this has something to do with the links behaviour being propogated to the child div, but am not sure.
Below is my script, the problem is in the last $('a').click(); function.
UPDATE:
I still need a better way to do it using just the $('a') selector if anyone knows how. Kind of a hack but, if i change the selector to $('a>div') and change the 'targetLink' to $(this).parent().attr('href') it seems to work, Is there a way to do this using $('a') only because some of my buttons have more children.
//Mobile accidental scroll click fix:---
//- prevent clicked link from executing if user scrolls after mousedown, until next mousedown.
//- prevent clicked link from executing if user is still scrolling and mouse is down(for slow scrolls)
$(document).ready(function(){
var self = this,
scrolling = false,
mouseDown = false,
scrollAfterPress = false;
scrollDelay = 1500,
linkConditionCheckDelay = 700;
$(window).scroll(function() {
self.scrolling = true;
console.log('scrolling:' + self.scrolling);
clearTimeout( $.data( this, "scrollCheck" ) );
$.data( this, "scrollCheck", setTimeout(function() {
self.scrolling = false;
console.log('scrolling:' + self.scrolling);
}, scrollDelay) );
});
$(document).mousedown(function(){
self.scrollAfterPress = false;
int00 = setInterval(function() { checkScrollAfterPress(); }, 100);//execute every 100ms (while mouse is down)
self.mouseDown = true;
console.log('mousedown:'+ self.mouseDown);
}).mouseup(function(){
clearInterval(int00);
self.mouseDown = false;
console.log('mousedown:'+ self.mouseDown);
});
function checkScrollAfterPress(){
if(self.scroll === true){
self.scrollAfterPress = true;
}
}
$('a').click(function(e){
//prevent default click event behaviour
var targetLink = $(this).attr('href');
console.log('clicked on:'+targetLink);
setTimeout(function() {
if(!self.scrolling && !self.mouseDown && !self.scrollAfterPress && targetLink !== undefined){
window.location.href = targetLink;
}
}, linkConditionCheckDelay); //add small delay to prevent immeditiate responses between mouse up and start of scroll.
e.stopPropagation();
e.preventDefault();
});
});
You can use return false or e.preventDefault
But when you click on that link why your adding window.location.href = targetLink;?? which will redirect the user to the given location.Same as link
Try my code below i have removed it.
$(document).ready(function(){
var self = this,
scrolling = false,
mouseDown = false,
scrollAfterPress = false;
scrollDelay = 1500,
linkConditionCheckDelay = 700;
$(window).scroll(function() {
self.scrolling = true;
console.log('scrolling:' + self.scrolling);
clearTimeout( $.data( this, "scrollCheck" ) );
$.data( this, "scrollCheck", setTimeout(function() {
self.scrolling = false;
console.log('scrolling:' + self.scrolling);
}, scrollDelay) );
});
$(document).mousedown(function(){
self.scrollAfterPress = false;
int00 = setInterval(function() { checkScrollAfterPress(); }, 100);//execute every 100ms (while mouse is down)
self.mouseDown = true;
console.log('mousedown:'+ self.mouseDown);
}).mouseup(function(){
clearInterval(int00);
self.mouseDown = false;
console.log('mousedown:'+ self.mouseDown);
});
function checkScrollAfterPress(){
if(self.scroll === true){
self.scrollAfterPress = true;
}
}
$('a').click(function(e){
//prevent default click event behaviour
var targetLink = $(this).attr('href');
console.log('clicked on:'+targetLink);
setTimeout(function() {
if(!self.scrolling && !self.mouseDown && !self.scrollAfterPress && targetLink !== undefined){
//window.location.href = targetLink;
}
}, linkConditionCheckDelay); //add small delay to prevent immeditiate responses between mouse up and start of scroll.
return false;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="http://www.google.com">
<div style="width:100%;height:80px;margin-bottom:50px;">test</div>
</a>
I will suggest another approach and use jQuery Mobile Events. Something like this:
*untested, but is the idea
// set global var 'locked'
var locked = false;
// locked var true while scrolling
jQuery(document).on('scrollstart', function() { locked = true; });
// locked var back to false when finish
jQuery(document).on('scrollstop', function() { locked = false; });
// bind 'tap' & 'click' events to 'a' tag
jQuery(document).on('tap click', 'a', function(event) {
// But before proceed, check locked var
if (locked) {
event.preventDefault;
return false;
} else {
// ok, proceed with the click and further events...
}
});
Docs/ref:
scrollstart event
scrollstop event
tap event
vclick event
.click()
Use in your $'a'.click(function(e){...} part return false; to prevent the default behavior.
In your case:
$('a').click(function(e){
var targetLink = $(this).attr('href');
console.log('clicked on:'+targetLink);
setTimeout(function() {
if(!self.scrolling && !self.mouseDown && !self.scrollAfterPress && targetLink !== undefined){
window.location.href = targetLink;
}
}, linkConditionCheckDelay);
return false;//Stops default behavior
});
Perhaps there is something I am missing, but I do not see why your code cannot be made as simple as the following:
$(document).ready(function () {
var is_scrolling = false;
var timeout = null;
$(window).scroll(function () {
is_scrolling = true;
if (timeout) {
clearTimeout(timeout);
}
timeout = setTimeout(function () {
is_scrolling = false;
}, 1500);
});
$('a').click(function (e){
if (is_scrolling) {
e.preventDefault();
}
});
});
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/