Detecting click on window scrollbar - javascript

I'm trying to pause the main window scroll when scrolling a table, which I've done but are having trouble enabling the main window scroll again after.
This function will pause the main window scroll when scrolling over table.
function preventWindowScroll() {
scrollTable = document.querySelector(".members-data");
if (scrollTable.contains(event.target)) {
var oldScrollPos = document.body.scrollTop;
window.onscroll = function () { window.scrollTo(0, oldScrollPos); };
} else {
// disable scrollTo in order to reenable main window pause
window.onscroll = function () {};
}
}
The problem is that if I try to scroll down by clicking and dragging the main window scrollbar it's still jammed by scrollTo.
I've tried doing an onclick event, but it doesn't work when clicking scrollbar.
document.body.onclick = function(e) {
scrollTable = document.querySelector(".members-data");
if (!scrollTable.contains(e.target)) {
window.onscroll = function () {};
}
};
I've also tried removing the event listener, but can't figure out where to put it.
document.body.removeEventListener('mousewheel', preventWindowScroll);
document.body.removeEventListener('DOMMouseScroll', preventWindowScroll);
If I could just detect when a user clicks on the main window scroll eit would work as intended.
note: I have achieved pausing the main window scroll other ways, but they all have slight drawbacks.
Thanks

I use this code. Works in Chrome.
yourTable.addEventListener('wheel', handleMouseScroll);
function handleMouseScroll(e) {
var delta = e.deltaY || e.detail || e.wheelDelta;
if (delta < 0 && this.scrollTop == 0) {
e.preventDefault();
}
if (delta > 0 && this.scrollHeight - this.clientHeight - this.scrollTop <= 1) {
e.preventDefault();
}
}

Related

After preventing the default scroll event, scrollIntoView(); doesn't work Properly on Firefox desktop?

In my scenario the code should prevent the the default scroll event and use scrollIntoView() to move the user to a specific section according to the scroll direction.
https://stackoverflow.com/a/4770179/9164633 I used this method to prevent the scroll default event.
And I detect the direction like so,
preventDefault(e) {
e.preventDefault();
if(this.waiting == false && this.forceInitialScroll != true) {
if(e.deltaY && e.deltaY > 7) {
this.scrollDirection = 'down';
this.checkScroll()
}else if(e.deltaY && e.deltaY < -7) {
this.scrollDirection = 'up';
this.checkScroll()
}else {
}
}
},
and Im pretty sure that both are working fine.
After preventing the scroll and detecting the scroll direction I try to scroll the user to the section like so,
checkScroll() {
let element;
if(this.scrollDirection == 'down' && this.scrollIndex != 4 ) {
element = document.getElementById(`section-${this.scrollIndex+1}`);
}else if(this.scrollDirection == 'up' && this.scrollIndex != 0) {
element = document.getElementById(`section-${this.scrollIndex-1}`);
}
this.waiting = true;
if(element) {
console.log(element)
element.scrollIntoView({
behavior: 'smooth',
block: 'center',
})
}
setTimeout(() => {
if(this.waiting == true) {
this.waiting = false;
this.scrollDirection = null;
}
}, 450)
},
this.waiting is used to prevent the user form scrolling more than one section at a time.
On firefox the browser doesnt scroll the user properly though its working fine on chrome.
Apparently Firefox's behavior with event.preventDefault() was that it blocked any kind of user scrolling and even the js manual scrolling.
The problem in my case was solved by hiding the scroll in css instead of js by using overflow: hidden; and then controlling the scroll manually instead of preventing the default behavior.

How to hit a function when scroll position is reaches the top position?

When scroll position hit the top position of the document the function is called. How to do that?
Good way to do it is to use the HostListener
#HostListener("window:scroll", [])
onWindowScroll() {
let scroll = this.window.pageYOffset || this.document.documentElement.scrollTop || this.document.body.scrollTop || 0;
if (number = 0) {
// Do some stuff here
}
}
Now I just wanna add that you probably need to account for elastic scroll on mac desktops. Meaning that your scroll position can go in minus, and might not hit 0 exactly when you want this event to fire.
Here is a good blog post about this, if you want more reading material
Use addEventListener on body, and listen for 'scroll' event, then when event is fired check scrollY property of window, and if it is 0, then you are on top.
function yourFunction() {
console.log('you are on top');
}
window.addEventListener('scroll', () => {
if (window.scrollY == 0) yourFunction();
}, true);
You can use HostListener to listen to the scroll event
#HostListener("window:scroll", ["$event"])
onWindowScroll() {
// get scroll postion
let number = this.window.pageYOffset ||
this.document.documentElement.scrollTop || this.document.body.scrollTop ||
0;
// here you can check the scroll postion
if (number > 100) {
}
}

How to determine scroll direction without actually scrolling

I am coding a page where the first time the user scrolls, it doesn't actually scroll the page down, instead it adds a class with a transition.
I'd like to detect when the user is scrolling down, because if he scrolls up, I want it to do something else.
All the methods that I've found are based on defining the current body ScrollTop, and then comparing with the body scrollTop after the page scrolls, defining the direction, but since the page doesn't actually scroll, the body scrollTop() doesn't change.
animationIsDone = false;
function preventScroll(e) {
e.preventDefault();
e.stopPropagation();
}
$('body').on('mousewheel', function(e) {
if (animationIsDone === false) {
$("#main-header").removeClass("yellow-overlay").addClass("yellow-overlay-darker");
$(".site-info").first().addClass("is-description-visible");
preventScroll(e);
setTimeout(function() {
animationIsDone = true;
}, 1000);
}
});
This is what I have come with, but that way it doesn't matter the direction I scroll it triggers the event
The mousewheel event is quickly becoming obsolete. You should use wheel event instead.
This would also easily allow you to the vertical and/or horizontal scroll direction without scroll bars.
This event has support in all current major browsers and should remain the standard far into the future.
Here is a demo:
window.addEventListener('wheel', function(event)
{
if (event.deltaY < 0)
{
console.log('scrolling up');
document.getElementById('status').textContent= 'scrolling up';
}
else if (event.deltaY > 0)
{
console.log('scrolling down');
document.getElementById('status').textContent= 'scrolling down';
}
});
<div id="status"></div>
Try This using addEventListener.
window.addEventListener('mousewheel', function(e){
wDelta = e.wheelDelta < 0 ? 'down' : 'up';
console.log(wDelta);
});
Demo
Update:
As mentioned in one of the answers, the mousewheel event is depreciated. You should use the wheel event instead.
I know this post is from 5 years ago but I didn't see any good Jquery answer (the .on('mousewheel') doesn't work for me...)
Simple answer with jquery, and use window instead of body to be sure you are taking scroll event :
$(window).on('wheel', function(e) {
var scroll = e.originalEvent.deltaY < 0 ? 'up' : 'down';
console.log(scroll);
});
Try using e.wheelDelta
var animationIsDone = false, scrollDirection = 0;
function preventScroll(e) {
e.preventDefault();
e.stopPropagation();
}
$('body').on('mousewheel', function(e) {
if (e.wheelDelta >= 0) {
console.log('Scroll up'); //your scroll data here
}
else {
console.log('Scroll down'); //your scroll data here
}
if (animationIsDone === false) {
$("#main-header").removeClass("yellow-overlay").addClass("yellow-overlay-darker");
$(".site-info").first().addClass("is-description-visible");
preventScroll(e);
setTimeout(function() {
animationIsDone = true;
}, 1000);
}
});
Note: remember that MouseWheel is deprecated and not supported in FireFox
this one work in react app
<p onWheel={this.onMouseWheel}></p>
after add event listener, in function u can use deltaY To capture mouse Wheel
onMouseWheel = (e) => {
e.deltaY > 0
? console.log("Down")
: console.log("up")
}
Tested on chrome and
$('body').on('mousewheel', function(e) {
if (e.originalEvent.deltaY >= 0) {
console.log('Scroll up'); //your scroll data here
}
else {
console.log('Scroll down'); //your scroll data here
}
});

Prevent scrollTop from calling scroll event

I'm trying to create this behavior: when user scrolls a mousewheel (or presses ↓) the webpage is scrolled down by the height of the window.
I've ended up with following code:
var newScrollTop,
oldScrollTop = $(window).scrollTop(),
preventScroll = false;
$(window).scroll(function() {
if (!preventScroll) {
preventScroll = true;
newScrollTop = $(this).scrollTop();
if (newScrollTop > oldScrollTop) {
$(this).scrollTop( oldScrollTop + $(window).height() );
}
else {
$(this).scrollTop( oldScrollTop - $(window).height() );
}
oldScrollTop = newScrollTop;
preventScroll = false;
}
});
But this doesn't work as I expect it: on scroll event page is scrolled to the very edge (bottom or top). What am I missing?
The issue is you're using scrollTop() which trigger a scroll event inside the window scroll event itself.
So basically, with the code you've written you run into an infinite loop because as soon as the first scroll event is triggered another one is triggered by scrollTop() while your preventScroll variable is still not set to false and so on.
To make your code work you would have to set your preventScroll variable to false inside the setTimeout function like so :
var newScrollTop,
oldScrollTop = $(window).scrollTop(),
preventScroll = false;
$(window).scroll(function() {
if (!preventScroll) {
preventScroll = true;
newScrollTop = $(this).scrollTop();
if (newScrollTop > oldScrollTop) {
$(this).scrollTop( oldScrollTop + $(window).height() );
}
else {
$(this).scrollTop( oldScrollTop - $(window).height() );
}
oldScrollTop = newScrollTop;
setTimeout(function(){ preventScroll = false; }, 0);
}
});
We add some "delay" before we set preventScroll to false.
This way when you call scrollTop() preventScroll variable will still be set to true !
Here's a working fiddle : http://jsfiddle.net/J6Fcm/ (I modified a little bit your code to let the scrolling steps work as expected)
There is no easy way of overriding the default browser scroll functionality. Here's one way of doing what you want, but it requires Brandon Aaron's jquery-mousewheel plugin to manage the mouse scrollwheel:
$(function() {
// Ugly hack to disable browser scrolling (downside: hides scrollbar!!!)
$('html').css('overflow', 'hidden');
// Get viewport height by which to scroll (up or down)
var viewportHeight = $(window).height();
// Recache viewport height on browser resize
$(window).on('resize', function() {
viewportHeight = $(window).height();
});
// Scroll on mousewheel
$('html').on('mousewheel', function(event, delta, deltaX, deltaY) {
// scroll down
if (deltaY < 0)
window.scrollBy(0, viewportHeight);
// scroll up
else
window.scrollBy(0, -viewportHeight);
});
// Disable document keypress event
// which would scroll the content even with "overlow: hidden"
$(document).on('keypress', function(){
return false;
});
// Scroll on arrow up/down keys
$(document).on('keydown', function(event){
// arrow down key
if (event.which == 40)
window.scrollBy(0, viewportHeight);
// arrow up key
if (event.which == 38)
window.scrollBy(0, -viewportHeight);
});
});
Here's a fiddle to demo the code. It all works very well except there is one ugly drawback to my solution. The $('html').css('overflow', 'hidden'); is removing the browser scrollbar.

Distinguishing between the user scrolling and programmatically scrolling using Javascript

I'm creating a scrolling effect using JQuery and I'm wondering if it's possible to distinguish between the user scrolling vs. programmatically scrolling.
I have something like this:
$('#element').on('scroll',function(e){
$('#element').stop(true); // stop previous scrolling animation
$('#element').animate({ // start new scrolling animation (maybe different speed, different direction, etc)
scrollTop:...
});
});
However, this event is triggered during every step of the animation. How can I tell if this event was triggered by the user or by the animation?
Use a variable to determine when you are scrolling programmatically
Example:
var programScrolling = false;
$('#element').on('scroll',function(e){
if (programScrolling) {
return;
}
$('#element').stop(true); // stop scrolling animation
programScrolling = true;
$('#element').animate({
scrollTop:...
});
programScrolling = false;
});
Not sure if that is exactly what you want, but the concept should work.
I would make functions for different kinds of scrollings to detect them and call a scroll handler for all of them, like so:
JS Fiddle
$(window).bind('mousewheel DOMMouseScroll', function(event){
var direction;
if (event.originalEvent.wheelDelta > 0 || event.originalEvent.detail < 0) {
direction = 'up';
}
else {
direction = 'down';
}
scrollHandler(direction, 'mouseWheel');
event.preventDefault();
});
var scrollHandler = function(direction, origin) {
var height = $(document).scrollTop();
var movement = (direction == 'up') ? -100 : 100;
console.log(origin);
$('body').stop(true);
$('body').animate({
scrollTop: height + movement
}, 250);
};
Then you can do different stuff according to the origin of the event!
You could also check if the user scrolls to the same direction that the screen is scrolling and do something different, or whatever you want with the info passed by the mousewheel event.
Original mousewheel event function copied from THIS answer
I would suggest possibly using the .originalEvent method. The downside is, this is very browser dependent. See here. Hopefully the following helps:
$('#element').scroll(function(e){
var humanScroll = e.originalEvent === undefined;
if(humanScroll) {
$(this).stop(true);
}
})

Categories

Resources