jquery window.scroll doesn't work properly - javascript

in this page I have 3 window.scroll functions but my events isn't working properly but if I remove another 2 window.scroll the very first window.scroll function works as expected.My jquery codes are in below
$(document).scroll(function() {
var y = $(this).scrollTop();
if (y > 800) {
$('.sizi-arayalim').fadeIn();
} else {
$('.sizi-arayalim').fadeOut();
}
});
$(document).scroll(function() {
if (!$("#aniStickyNav").length) {
return false; //Check if the element exist
}
var y = $(this).scrollTop();
if (y > $(".after-scroll-sticky").offset().top+$(".hotel-search-box").height()) {
$('#aniStickyNav').show();
} else {
$('#aniStickyNav').hide();
}
});
$(document).scroll(function(){
if(!$(".hotel-search-box").length){
return false;
}
var y = $(this).scrollTop();
if (y > $(".hotel-search-box").offset().top) {
$('.sticky-checkin').show();
} else {
$('.sticky-checkin').hide();
}
});

you can use if (!$("#aniStickyNav").length) {
return false;
without putting into scroll function,
and try to combine others into just one.

Related

classList and scroll event

I have some simple script to adding classes to my navbar relied on pageYOffset:
var navContainer = document.querySelector('.nav-container');
var firstTitle = document.querySelector('.first-title')
document.addEventListener('scroll',function(){
if(window.pageYOffset < 75){
navContainer.classList.remove('nav-action','yellow');
}else if(window.pageYOffset > 75){
navContainer.classList.add('nav-action')
}else if(window.pageYOffset<firstTitle.offsetTop){
navContainer.classList.remove('yellow');
}
else if(window.pageYOffset > firstTitle.offsetTop){
navContainer.classList.add('yellow');
};
});
my trouble is this that last condition is fulfilled when window.pageYOffset is bigger than firstTitle.offsetTop, writing this line between brackets in the console returns true, but nothing happens when I'm trying this all code.
Unless window.pageYOffset === 75, none of these lines will actually be executed. The previous conditions already catch all the cases.
I would suggest treating nav-action and yellow separately:
var navContainer = document.querySelector('.nav-container');
var firstTitle = document.querySelector('.first-title')
document.addEventListener('scroll', function() {
if (window.pageYOffset < 75) {
navContainer.classList.remove('nav-action');
} else {
navContainer.classList.add('nav-action')
}
if (window.pageYOffset < firstTitle.offsetTop) {
navContainer.classList.remove('yellow');
} else {
navContainer.classList.add('yellow');
}
});

Is there any way to combine (collect) all scroll functions?

I have more than one scroll function like this:
FIRST
$(document).scroll(function(){
if(!$(".hotel-search-box").length){
return false;
}
var y = $(this).scrollTop();
if (y > $(".hotel-search-box").offset().top) {
$('.sticky-checkin').show();
} else {
$('.sticky-checkin').hide();
}
});
SECOND
$(document).scroll(function() {
if (!$("#aniStickyNav").length) {
return false; //Check if the element exist
}
var y = $(this).scrollTop();
if (y > $(".after-scroll-sticky").offset().top+$(".hotel-search-box").height()) {
$('#aniStickyNav').show();
} else {
$('#aniStickyNav').hide();
}
});
THIRD
$(window).on('scroll', function () {
backToTop();
});
I tried this way:
$(window).scroll(function(){
function siziArayalim(){
var y = $(this).scrollTop();
if (y > 800) {
$('.sizi-arayalim').fadeIn();
} else {
$('.sizi-arayalim').fadeOut();
}
}
function aniStickyNav(){
if (!$("#aniStickyNav").length) {
return false; //Check if the element exist
}
var y = $(this).scrollTop();
if (y > $(".after-scroll-sticky").offset().top+$(".hotel-search-box").height()) {
$('#aniStickyNav').show();
} else {
$('#aniStickyNav').hide();
}
}
function stickyCheckin(){
if(!$(".hotel-search-box").length){
return false;
}
var y = $(this).scrollTop();
if (y > $(".hotel-search-box").offset().top) {
$('.sticky-checkin').show();
} else {
$('.sticky-checkin').hide();
}
}
siziArayalim();
aniStickyNav();
stickyCheckin();
});
but nothing works.
Because of more than one scroll function some js functions are not working as expected that is why I wonder that how to combine all window.scroll function in a just one function healthy?
There are some issues with your code, first one is that you declare your functions inside the scroll function. This is not OK for performance. The second one is $(this) you are using inside the functions. I don't know what "this" is. In that context you are using, this will be the window object but i don't think that's what you need. Need more info here.
function siziArayalim(){
var y = $(this).scrollTop();
if (y > 800) {
$('.sizi-arayalim').fadeIn();
} else {
$('.sizi-arayalim').fadeOut();
}
}
function aniStickyNav(){
if (!$("#aniStickyNav").length) {
return false; //Check if the element exist
}
var y = $(this).scrollTop();
if (y > $(".after-scroll-sticky").offset().top+$(".hotel-search-box").height()) {
$('#aniStickyNav').show();
} else {
$('#aniStickyNav').hide();
}
return true;
}
function stickyCheckin(){
if(!$(".hotel-search-box").length){
return false;
}
var y = $(this).scrollTop();
if (y > $(".hotel-search-box").offset().top) {
$('.sticky-checkin').show();
} else {
$('.sticky-checkin').hide();
}
return true;
}
$(window).scroll(function(){
siziArayalim();
// check if the functions return false, if not, continue
if(!aniStickyNav()){
return false;
}
if(!stickyCheckin()){
return false;
}
});

Detect touch scroll up or down

I need code same this for touch devices . help me please
$(window).on('DOMMouseScroll mousewheel', function (e) {
if (ScrollEnable) {
if (e.originalEvent.detail > 0 || e.originalEvent.wheelDelta < 0) {
console.log('Down');
} else {
console.log('Up');
}
}
return false;
});
and here is my touch code, But consul just take up i need find down for my website ! what can i do :|
$('body').on({
'touchmove': function(e) {
if (e.originalEvent.touches > 0 || e.originalEvent.touches > 0) {
console.log('Down');
} else {
console.log('Up');
}
}
});
var updated=0,st;
$('body').on({
'touchmove': function(e) {
st = $(this).scrollTop();
if(st > updated) {
console.log('down');
}
else {
console.log('up');
}
updated = st;
}
});
You can use scroll event
var lastScrollTop = 0;
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
// downscroll code
} else {
// upscroll code
}
lastScrollTop = st;
});
I know my solution is a bit more generic - it is not dependend on any element, but it might help someone that has encountered the same problem as me.
var touchPos;
// store the touching position at the start of each touch
document.body.ontouchstart = function(e){
touchPos = e.changedTouches[0].clientY;
}
// detect wether the "old" touchPos is
// greater or smaller than the newTouchPos
document.body.ontouchmove = function(e){
let newTouchPos = e.changedTouches[0].clientY;
if(newTouchPos > touchPos) {
console.log("finger moving down");
}
if(newTouchPos < touchPos) {
console.log("finger moving up");
}
}
The only way that I could (and tested) detect scroll down/up on mobile devices (android & ios, touch devices):
(other events such as scroll, mousewheel, DOMMouseScroll, nmousewheel and wheel do not work on mobile devices)
jQuery:
let touchStartPosX = 0;
// Detect Scroll Down and Up in mobile(android|ios)
$(window).on('touchmove', (e) => {
// Different devices give different values with different decimal percentages.
const currentPageX = Math.round(e.originalEvent.touches[0].screenY);
if (touchStartPosX === currentPageX) return;
if (touchStartPosX - currentPageX > 0) {
console.log("down");
} else {
console.log("up");
}
touchStartPosX = currentPageX;
});
Vanilla:
let touchStartPosX = 0;
window.addEventListener('touchmove', (e) => {
// Different devices give different values with different decimal percentages.
const currentPageX = Math.round(e.changedTouches[0].screenY);
if (touchStartPosX === currentPageX) return;
if (touchStartPosX - currentPageX > 0) {
console.log("down");
} else {
console.log("up");
}
touchStartPosX = currentPageX;
});
This w3schools.com documentation would help you out http://www.w3schools.com/jquerymobile/jquerymobile_events_scroll.asp
$(document).on("scrollstop",function(){
alert("Stopped scrolling!");
});

Detecting scroll direction

So I am trying to use the JavaScript on scroll to call a function. But I wanted to know if I could detect the direction of the the scroll without using jQuery. If not then are there any workarounds?
I was thinking of just putting a 'to top' button but would like to avoid that if I could.
I have now just tried using this code but it didn't work:
if document.body.scrollTop <= 0 {
alert ("scrolling down")
} else {
alert ("scrolling up")
}
It can be detected by storing the previous scrollTop value and comparing the current scrollTop value with it.
JavaScript :
var lastScrollTop = 0;
// element should be replaced with the actual target element on which you have applied scroll, use window in case of no target element.
element.addEventListener("scroll", function(){ // or window.addEventListener("scroll"....
var st = window.pageYOffset || document.documentElement.scrollTop; // Credits: "https://github.com/qeremy/so/blob/master/so.dom.js#L426"
if (st > lastScrollTop) {
// downscroll code
} else if (st < lastScrollTop) {
// upscroll code
} // else was horizontal scroll
lastScrollTop = st <= 0 ? 0 : st; // For Mobile or negative scrolling
}, false);
Simple way to catch all scroll events (touch and wheel)
window.onscroll = function(e) {
// print "false" if direction is down and "true" if up
console.log(this.oldScroll > this.scrollY);
this.oldScroll = this.scrollY;
}
Use this to find the scroll direction. This is only to find the direction of the Vertical Scroll. Supports all cross browsers.
var scrollableElement = document.body; //document.getElementById('scrollableElement');
scrollableElement.addEventListener('wheel', checkScrollDirection);
function checkScrollDirection(event) {
if (checkScrollDirectionIsUp(event)) {
console.log('UP');
} else {
console.log('Down');
}
}
function checkScrollDirectionIsUp(event) {
if (event.wheelDelta) {
return event.wheelDelta > 0;
}
return event.deltaY < 0;
}
Example
You can try doing this.
function scrollDetect(){
var lastScroll = 0;
window.onscroll = function() {
let currentScroll = document.documentElement.scrollTop || document.body.scrollTop; // Get Current Scroll Value
if (currentScroll > 0 && lastScroll <= currentScroll){
lastScroll = currentScroll;
document.getElementById("scrollLoc").innerHTML = "Scrolling DOWN";
}else{
lastScroll = currentScroll;
document.getElementById("scrollLoc").innerHTML = "Scrolling UP";
}
};
}
scrollDetect();
html,body{
height:100%;
width:100%;
margin:0;
padding:0;
}
.cont{
height:100%;
width:100%;
}
.item{
margin:0;
padding:0;
height:100%;
width:100%;
background: #ffad33;
}
.red{
background: red;
}
p{
position:fixed;
font-size:25px;
top:5%;
left:5%;
}
<div class="cont">
<div class="item"></div>
<div class="item red"></div>
<p id="scrollLoc">0</p>
</div>
Initialize an oldValue
Get the newValue by listening to the event
Subtract the two
Conclude from the result
Update oldValue with the newValue
// Initialization
let oldValue = 0;
//Listening on the event
window.addEventListener('scroll', function(e){
// Get the new Value
newValue = window.pageYOffset;
//Subtract the two and conclude
if(oldValue - newValue < 0){
console.log("Up");
} else if(oldValue - newValue > 0){
console.log("Down");
}
// Update the old value
oldValue = newValue;
});
This is an addition to what prateek has answered.There seems to be a glitch in the code in IE so i decided to modify it a bit nothing fancy(just another condition)
$('document').ready(function() {
var lastScrollTop = 0;
$(window).scroll(function(event){
var st = $(this).scrollTop();
if (st > lastScrollTop){
console.log("down")
}
else if(st == lastScrollTop)
{
//do nothing
//In IE this is an important condition because there seems to be some instances where the last scrollTop is equal to the new one
}
else {
console.log("up")
}
lastScrollTop = st;
});});
While the accepted answer works, it is worth noting that this will fire at a high rate. This can cause performance issues for computationally expensive operations.
The recommendation from MDN is to throttle the events. Below is a modification of their sample, enhanced to detect scroll direction.
Modified from: https://developer.mozilla.org/en-US/docs/Web/API/Document/scroll_event
// ## function declaration
function scrollEventThrottle(fn) {
let last_known_scroll_position = 0;
let ticking = false;
window.addEventListener("scroll", function () {
let previous_known_scroll_position = last_known_scroll_position;
last_known_scroll_position = window.scrollY;
if (!ticking) {
window.requestAnimationFrame(function () {
fn(last_known_scroll_position, previous_known_scroll_position);
ticking = false;
});
ticking = true;
}
});
}
// ## function invocation
scrollEventThrottle((scrollPos, previousScrollPos) => {
if (previousScrollPos > scrollPos) {
console.log("going up");
} else {
console.log("going down");
}
});
This simple code would work: Check the console for results.
let scroll_position = 0;
let scroll_direction;
window.addEventListener('scroll', function(e){
scroll_direction = (document.body.getBoundingClientRect()).top > scroll_position ? 'up' : 'down';
scroll_position = (document.body.getBoundingClientRect()).top;
console.log(scroll_direction);
});
You can get the scrollbar position using document.documentElement.scrollTop. And then it is simply matter of comparing it to the previous position.
If anyone looking to achieve it with React hooks
const [scrollStatus, setScrollStatus] = useState({
scrollDirection: null,
scrollPos: 0,
});
useEffect(() => {
window.addEventListener("scroll", handleScrollDocument);
return () => window.removeEventListener("scroll", handleScrollDocument);
}, []);
function handleScrollDocument() {
setScrollStatus((prev) => { // to get 'previous' value of state
return {
scrollDirection:
document.body.getBoundingClientRect().top > prev.scrollPos
? "up"
: "down",
scrollPos: document.body.getBoundingClientRect().top,
};
});
}
console.log(scrollStatus.scrollDirection)
I personally use this code to detect scroll direction in javascript...
Just you have to define a variable to store lastscrollvalue and then use this if&else
let lastscrollvalue;
function headeronscroll() {
// document on which scroll event will occur
var a = document.querySelector('.refcontainer');
if (lastscrollvalue == undefined) {
lastscrollvalue = a.scrollTop;
// sets lastscrollvalue
} else if (a.scrollTop > lastscrollvalue) {
// downscroll rules will be here
lastscrollvalue = a.scrollTop;
} else if (a.scrollTop < lastscrollvalue) {
// upscroll rules will be here
lastscrollvalue = a.scrollTop;
}
}
Modifying Prateek's answer, if there is no change in lastScrollTop, then it would be a horizontal scroll (with overflow in the x direction, can be used by using horizontal scrollbars with a mouse or using scrollwheel + shift.
const containerElm = document.getElementById("container");
let lastScrollTop = containerElm.scrollTop;
containerElm.addEventListener("scroll", (evt) => {
const st = containerElm.scrollTop;
if (st > lastScrollTop) {
console.log("down scroll");
} else if (st < lastScrollTop) {
console.log("up scroll");
} else {
console.log("horizontal scroll");
}
lastScrollTop = Math.max(st, 0); // For mobile or negative scrolling
});
This seems to be working fine.
document.addEventListener('DOMContentLoaded', () => {
var scrollDirectionDown;
scrollDirectionDown = true;
window.addEventListener('scroll', () => {
if (this.oldScroll > this.scrollY) {
scrollDirectionDown = false;
} else {
scrollDirectionDown = true;
}
this.oldScroll = this.scrollY;
// test
if (scrollDirectionDown) {
console.log('scrolling down');
} else {
console.log('scrolling up');
}
});
});
Sometimes there are inconsistencies in scrolling behavior which does not properly update the scrollTop attribute of an element. It would be safer to put some threshold value before deciding the scroll direction.
let lastScroll = 0
let threshold = 10 // must scroll by 10 units to know the direction of scrolling
element.addEventListener("scroll", () => {
let newScroll = element.scrollTop
if (newScroll - lastScroll > threshold) {
// "up" code here
} else if (newScroll - lastScroll < -threshold) {
// "down" code here
}
lastScroll = newScroll
})
let arrayScroll = [];
window.addEventListener('scroll', ()=>{
arrayScroll.splice(1); //deleting unnecessary data so that array does not get too big
arrayScroll.unshift(Math.round(window.scrollY));
if(arrayScroll[0] > arrayScroll[1]){
console.log('scrolling down');
} else{
console.log('scrolling up');
}
})
I have self-made the above solution. I am not sure if this solution may cause any considerable performance issue comparing other solutions as I have just started learning JS and not yet have completed my begginer course. Any suggestion or advice from experienced coder is highly appriciated. ThankYou!

Treating each div as a "page" when scrolling

I have a page that I'm building and I would like to make it that when I scroll (up or down) the page scrolls to the next div (each div is 100% the height of the window). And gets "fixed" there until you scroll again. An example of what I'm trying to accomplish can be seen here:
http://testdays.hondamoto.ch/
You will notice that when you scroll down, it automatically moves you to the next "div".
What I've tried:
Using the jQuery .scroll event combined with:
function updatePosition() {
if(canScroll) {
var pageName;
canScroll = false;
var st = $(window).scrollTop();
if (st > lastScrollTop){
// downscroll code
if(pageNumber < 7) {
pageNumber++;
}
pageName = '#' + getPageToScrollTo().id;
$('body').animate({ scrollTop: $(pageName).offset().top }, 2000, function() {
canScroll = true;
});
} else {
// upscroll code
if(pageNumber > 0) {
pageNumber--;
}
pageName = '#' + getPageToScrollTo().id;
$('body').animate({ scrollTop: $(pageName).offset().top }, 2000, function() {
canScroll = true;
});
}
lastScrollTop = st;
}
}
But the scroll event was getting called when the page was scrolling (animating), AND when the user scrolled. I only need it to be called when the user scrolls.
Then I added:
var throttled = _.throttle(updatePosition, 3000);
$(document).scroll(throttled);
From the Underscore.js library - but it still did the same.
Finally, I browsed here a bit and found:
Call Scroll only when user scrolls, not when animate()
But I was unable to implement that solution. Is there anyone that knows of any libraries or methods to get this working?
EDIT:
Solution based on Basic's answer:
function nextPage() {
canScroll = false;
if(pageNumber < 7) {
pageNumber++;
}
pageName = getPageToScrollTo();
$('html, body').stop().animate({ scrollTop: $(pageName).offset().top }, 1000, function() {
canScroll = true;
});
}
function prevPage() {
canScroll = false;
if(pageNumber > 0) {
pageNumber--;
}
pageName = getPageToScrollTo();
$('html, body').stop().animate({ scrollTop: $(pageName).offset().top }, 1000, function() {
canScroll = true;
});
}
//--Bind mouseWheel
$(window).on(mousewheelevt, function(event) {
event.preventDefault();
if(canScroll){
if(mousewheelevt == "mousewheel") {
if (event.originalEvent.wheelDelta >= 0) {
prevPage();
} else {
nextPage();
}
} else if(mousewheelevt == "DOMMouseScroll") {
if (event.originalEvent.detail >= 0) {
nextPage();
} else {
prevPage();
}
}
}
});
Ok...
The relevant code for the Honda site can be found in http://testdays.hondamoto.ch/js/script_2.js. It seems to be doing some calculations to locate the top of the div then scroll to it. There are handlers for different types of scrolling.
Specifically, the movement is handled by function navigation(target)
the key bits is here...
$('html,body').stop().animate({
scrollTop: $(target).offset().top + newMargin
}, 1000,'easeInOutExpo',function(){
//Lots of "page"-specific stuff
}
});
There are handlers for the scroll types...
$('body').bind('touchstart', function(event) {
//if(currentNav!=3){
// jQuery clones events, but only with a limited number of properties for perf reasons. Need the original event to get 'touches'
var e = event.originalEvent;
scrollStartPos = e.touches[0].pageY;
//}
});
//--Bind mouseWheel
$('*').bind('mousewheel', function(event, delta) {
event.preventDefault();
//trace('class : '+$(this).attr('class') + ' id : '+$(this).attr('id'));
if(!busy && !lockScrollModel && !lockScrollMap){
if(delta<0){
nextPage();
}else{
prevPage();
}
}
});
You'll note that the navigate() function sets a busy flag which is unset when scrolling completes - which is how it suppresses all new scroll events during a scroll. Try changing the direction of scroll while the page is already scrolling and you'll notice user input is being ignored too.

Categories