React.js Scroll Threshold for Revealing Navigation - javascript

Using React.js, another dev wrote this code to toggle the appearance of a navigation element called ArticleNav. It reveals itself as your scrolling down but hides itself when you scroll back up.
onScroll: function () {
var mainColumn = document.getElementsByClassName('main-column')[0];
var firstTextElement = mainColumn.querySelector('.dek');
if (!firstTextElement) {
firstTextElement = mainColumn.querySelector('.body-text');
}
if (window.scrollY >= firstTextElement.offsetTop) {
if (!this.state.hideForArticleNav) {
this.setState({hideForArticleNav: true});
}
} else {
if (this.state.hideForArticleNav) {
this.setState({hideForArticleNav: false});
}
}
}
This works great but the use of if (window.scrollY >= firstTextElement.offsetTop) makes this jump back and forth too rapidly and I wanted to create a, let's say..., 50px threshold to confirm that the user is actually scrolling in the opposite direction.
Do y'all have any recommendations on how to approach this? I am more jQuery-minded than React, so all of my normal fixes don't exactly translate here.

I feel like I'm missing part of your question. Can't you simply add 50 px to the firstTextElement.offsetTop?
window.scrollY >= firstTextElement.offsetTop + 50

It sounds like you have a good setup to determine whether the user is scrolling up or down, so instead of setting this.state.hideForArticleNav you could set this.state.lastDirectionChangeOffset to the current window offset when the direction changes. Then you can check against that state value to see if it's +/- 50px.
onScroll: function () {
var mainColumn = document.getElementsByClassName('main-column')[0];
var firstTextElement = mainColumn.querySelector('.dek');
if (!firstTextElement) {
firstTextElement = mainColumn.querySelector('.body-text');
}
if (window.scrollY >= firstTextElement.offsetTop) {
if (!this.state.hideForArticleNav) {
this.setState({ lastDirectionChangeOffset: window.scrollY });
}
} else {
if (this.state.hideForArticleNav) {
this.setState({ lastDirectionChangeOffset: window.scrollY });
}
}
if (window.scrollY > this.state.lastDirectionChangeOffset + 50) {
this.setState({ hideForArticleNav: true })
} else if (window.scrollY < this.state.lastDirectionChangeOffset - 50) {
this.setState({ hideForArticleNav: false })
}
}

Related

How to back to className when menu is hide

I would like to make mobile menu witch changing background color and height from(10% to 100%. When menu is active nav—active hover all page for darkening)
const nav = document.getElementById("navigation");
const burger = document.getElementById("mobileBurger");
const menu = document.getElementById("mobileMenu");
burger.addEventListener("click", function() {
nav.classList.toggle("nav--active");
if (nav.classList.contains("nav--scroll")) {
nav.classList.remove("nav--scroll");
}
console.log(nav.classList.contains("nav"));
});
window.addEventListener("scroll", function() {
let scrolled = window.pageYOffset;
if (scrolled >= 40) {
nav.classList.add("nav--scroll");
} else nav.classList.remove("nav--scroll");
});
When nav is „nav—scrolled”, and I click on button, then I would like to leave only class=„nav nav—active”. Ok I did this, but how to back to „nav—scrolled” after hide menu. Of course only when it had this class?
I took a stab at it for you, but the html would be helpful to test it.
Notice moved the scroll check to a separate function to call when needed.
const nav = document.getElementById("navigation");
const burger = document.getElementById("mobileBurger");
const menu = document.getElementById("mobileMenu");
burger.addEventListener("click", function() {
// toggle returns a true or false based on if it adds/removes
if( nav.classList.toggle("nav--active") == false) {
// if it added (made inactive), lets check and see if scroll also applies.
checkScrolled();
} else {
if (nav.classList.contains("nav--scroll")) {
nav.classList.remove("nav--scroll");
}
}
console.log(nav.classList.contains("nav"));
});
window.addEventListener("scroll", function() {
checkScrolled();
});
function checkScrolled() {
let scrolled = window.pageYOffset;
if (scrolled >= 40 && nav.classList.contains("nav--scroll") == false) {
nav.classList.add("nav--scroll");
} else {
nav.classList.remove("nav--scroll");
}
}

Add class after scrolling also need to work on refresh

I have a working script which adds a class to the body after scrolling 80px.
This works but I need it to work too after having already scrolled and then refreshing the page.
So maybe replace the scroll part by position?
// fixed header
$(function() {
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 80) {
$("body").addClass('fixed');
} else {
$("body").removeClass("fixed");
}
});
});
$(window).scroll will only fire once a scroll event occurs. If you want to check for the scroll position when the page loads, you should do this outside of the $(window).scroll callback, like this:
function updateScroll() {
if ($(window).scrollTop() >= 80) {
$("body").addClass('fixed');
} else {
$("body").removeClass("fixed");
}
}
$(function() {
$(window).scroll(updateScroll);
updateScroll();
});
you're right. you need to check the event and the initial value:
window.addEventListener('load', function() {
var scroll = $(window).scrollTop();
if (scroll >= 80) {
$("body").addClass('fixed');
}
//no removing needed cause refresh did it
});
window.onscroll = function () { scrollFunction() };
function scrollFunction() {
if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) {
document.querySelector(".fixed-top").classList.add("headerFix");
} else {
document.querySelector(".fixed-top").classList.remove("headerFix");
}
}

Why my fix menu in not working smoothly on scrolling.

$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 5) {
$('#page-header').addClass('fixed');
} else {
$('#page-header').removeClass('fixed');
}
}).scroll();
Why my fix menu in not working smoothly on scrolling. i am using in my moodle theme frontpage.php or i have to add some thing for smoothness.
You're modifying the DOM too frequently, as $(window).scroll fires multiple times in a single scroll. Consider checking the existence of the class before add or remove it.
$(window).scroll(function() {
var windscroll = $(window).scrollTop();
if (windscroll >= 5) {
if(!$('#page-header').hasClass('fixed')) {
$('#page-header').addClass('fixed');
}
} else {
if(!$('#page-header').hasClass('fixed')) {
$('#page-header').removeClass('fixed');
}
}
});
also, I removed an extra .scroll() call at the end of the script.
Alternatively, you can make use of a jQuery On Screen plugin which will add a pseudo class :onscreen with the div visible in the browser. Codes are as follow:
$(document).scroll(function() {
if($("#page-header").is(':onScreen')) {
console.log("Element appeared on Screen");
if(!$('#page-header').hasClass('fixed')) {
$('#page-header').addClass('fixed');
}
} else {
console.log("Element not on Screen");
if(!$('#page-header').hasClass('fixed')) {
$('#page-header').removeClass('fixed');
}
}
});
See if the plugin fits your needs.

Having trouble in speeding up scroll animation using javascript

I have below code. What it does is when user scrolls up/down the contents of the div scrolls accordingly but smoothly. At the moment, the code works ok but the scrolling up/down animation is too slow. How can I make it a bit faster?
Below is JS code
function onMouseScroll (e) {
var detail = e.detail,
wheelDelta = e.wheelDelta;
if (detail) {
if (wheelDelta && (f = wheelDelta/detail)) {
detail = detail/f;
} else {
detail = -detail/1.35;
}
} else {
detail = wheelDelta/120;
}
scroll(offset + detail);
e.preventDefault();
e.stopPropagation();
return false;
}
You can change the speed at line 23. If you decrease the number, the speed increases.
detail = wheelDelta/120;

How to detect user mouse wheel scroll distance?

I am trying to detect user scroll, if to left and to right then trigger and do something.
But if user use trackpad scroll to top or to bottom then it will accidentally scroll to left or to right.
I think, may be not just check timer define per scroll also need to check if user scroll distance smaller than 20, we can differentiate that as accidentally and don't do anything.
I can't find the way check if user scroll distance, the element is not be scrollable so can't use scrollTop scrollLeft....
Any idea?
var scroll_timer;
$('img').bind('mousewheel', function(e) {
if (e.originalEvent.wheelDeltaX < 0) {
clearTimeout(scroll_timer);
scroll_timer = setTimeout(function() {
// .. do something
// console.log('right');
}, 200);
} else if (e.originalEvent.wheelDeltaX > 0) {
clearTimeout(scroll_timer);
scroll_timer = setTimeout(function() {
// .. do something
// console.log('left');
}, 200);
}
});
Here is my JSFiddle
It looks like you can use e.originalEvent.wheelDeltaX to get scroll distance values. You could then use e.originalEvent.wheelDeltaY to see if the user is scrolling vertically more than horizontally and trigger stuff after that is true.
Here's a demo that works by testing if the value of scrolling Y is less that scrolling X and then allowing you to trigger if it's left or right after that. Seems to do the trick on my mac trackpad
var scroll_timer;
$('img').bind('mousewheel', function(e) {
if((Math.abs(e.originalEvent.wheelDeltaX) > Math.abs(e.originalEvent.wheelDeltaY)))
{
if (e.originalEvent.wheelDeltaX < 0) {
clearTimeout(scroll_timer);
scroll_timer = setTimeout(function() {
// .. do something
console.log('right');
}, 200);
} else if (e.originalEvent.wheelDeltaX > 0) {
clearTimeout(scroll_timer);
scroll_timer = setTimeout(function() {
// .. do something
console.log('left');
}, 200);
}
}
});
http://jsfiddle.net/andyface/5CfgT/

Categories