can I triggering Scroll Event based on Section - javascript

Is there a way of triggering a scroll event based on either section or div, and not on window page Y offset? For example I want the event to start on first section and then skip second and having an animation on 3rd. Is there a way of scripting it without window page Y offset > X amount of pixels, basically so that I'm not forced to calculate pixels over and over...
Currently, I am doing something like this:
window.addEventListener('scroll', ()=>{
if (window.pageYOffset > 100){
console.log('after')
} else {
console.log('before')
}
})

Related

Determine source of 'onscroll' event

I have a listener for the 'onscroll' event of window. In that handler I need to somehow figure out what triggered the event, e.g. I am running an animation which triggers window.scrollTo(x, y) and the listener should have different behaviour, if the event was triggered by the animation. More precisely, in case the user scrolls while the animation is running, I have to stop the animation. Is it even possible to pass a context to the event handler when I trigger window.scrollTo(x, y) or is there some hacky workaround to achieve this?
Here is some pseudo code of what I am trying to achieve:
let isAnimationRunning = false
function onScrollHandler(e) {
const isTriggeredByOnAnimationTick = // how to figure that one out???
if (isAnimationRunning && !isTriggeredByOnAnimationTick) {
stopAnimation()
}
// do something else
}
// called every key frame (requestAnimationFrame)
function onAnimationTick(scrollY) {
// will trigger onscroll handler at some point in time
window.scrollTo(0, scrollY)
}
window.addEventListener('scroll', onScrollHandler)
runAnimation(onAnimationTick)
I already thought about using different handlers for mousewheel and touch events on mobile. However, with that approach I encountered two problems:
One has to come up with another hack to figure out, whether the user scrolls via scrollbar
On mobile devices scrolling is decelerated after the touch gesture ends, thus I can not really figure out when the scroll event stops without using the onscoll handler.
Instead of detecting the users scroll we could rather check the position to the one we wanted to land at. If that changes the user has probably scrolled:
function scroll(x,y,end,interrupt,requireX, requireY){
//the movement applied after each loop
const speedX = 1, speedY = 1;
//check if the scrolled amount is not what we expect
if(requireX && requireX !== scrollX ||
requireY && requireY !== scrollY ) return interrupt();
//check if we reached our position
if( Math.abs(x - scrollX) < speedX &&
Math.abs(y - scrollY) < speedY
) return end();
//now finally scroll using window.scrollBy
scrollBy(
x > scrollX ? speedX : -speedX,
y > scrollY ? speedY : -speedY
);
//next iteration in 10ms
setTimeout(scroll, 10, x, y, end, interrupt,scrollX, scrollY) ;
}
The whole thing is then usable as:
scroll(
1000, //x to scroll to
0, //y to scroll to
_=>alert("finish"), //end handler
_=>alert("interrupt") //user interrupted handler
);
Try it

Stop element from scrolling at the footer

So I'm trying to get this element to scroll which it does but I'd like it to stop scrolling before the footer.
At the moment I have this but the pages don't have the same length so the >= 17900 is not a good solution for me.
$(window).scroll(function (event) {
var windowTop = $(this).scrollTop();
if (windowTop >= 17900) {
$(".product-form__item--quantity").addClass("non-fixed");
$(".product-form__item--submit").addClass("non-fixed");
$("#ProductPhotoImg").addClass("non-fixed");
$("#option_total").addClass("non-fixed");
$(".product-single__title").addClass("non-fixed");
$(".product-form__item--quantity").removeClass("change");
$(".product-form__item--submit").removeClass("change");
$("#ProductPhotoImg").removeClass("change");
$("#option_total").removeClass("change-option");
$(".product-single__title").removeClass("change");
} else {
//console.log('a');
$(".product-form__item--quantity").removeClass("non-fixed");
$(".product-form__item--submit").removeClass("non-fixed");
$("#ProductPhotoImg").removeClass("non-fixed");
$("#option_total").removeClass("non-fixed");
$(".product-single__title").removeClass("non-fixed");
}
});
Thanks for the help
You have more issues than only finding the footer's position here...
First is to find the position of the footer instead of hardcoding a value.
Okay...
Second is that you constantly add and remove classes on scroll.
This sure isn't the desired effect.
The scroll event fires like a dozen times or more on a single mouse wheel spin.
Third is that you force jQuery to lookup for elements, as #Taplar mentionned in comments, each times the script executes (Which is real bad if the script execute constantly!!). This is bad... And unuseful, since this those elements don't change.
So I modified your script... Almost completely :
;)
// Define an element collection ONCE.
var elementsList = $(".product-form__item--quantity, .product-form__item--submit, #ProductPhotoImg, #option_total, .product-single__title");
// Find the footer's position.
var footerPosition = $("#footer").offset().top;
// Set a flag to prevent the the script action when already done.
var footerVisible = false;
$(window).scroll(function (event) {
// How many pixels scrolled + viewport height = position of the last pixel at the bottom of the viewport relative to the document's top.
var viewportBottom = $(this).scrollTop() + $( window ).height();
if (viewportBottom >= footerPosition) {
if(!footerVisible){
// Will update classes on the element in the elementslist collection on user scroll enought to show the footer in viewport.
elementsList.addClass("non-fixed").removeClass("change change-option");
// Set a flag
footerVisible = true;
}
} else {
if(footerVisible){
// Will update classes on the element in the elementslist collection on user scroll from a "visible footer" to a footer below the viewport.
// In other words, You don't want to do it CONSTANTLY except when the footer is visible and dissapears due to user scroll up.
elementsList.removeClass("non-fixed");
// reset the flag.
footerVisible = false;
}
}
});

force stop scrolling on reaching the end of a scrollspy section

here is a fiddle to know where I am starting from
The problem I am looking to solve involves "paginating" content of a single html file, in such a way that locks them into a single section at a time. I want it so that when users scroll to the bottom of a section, it will slide up a prompt to move to the next page, which will fire a transition, such as different easing/from bottom and put them "in" the next section.
This would be repeated in the next section; when they scroll to the top, they will get a "previous" button but be unable to move unless they click "previous". If they hit the bottom, they will be unable to move to the next page without clicking "next". If they click a section tab, it would do the transition and bring them to that page from their current
I know that this will stop scrolling, but how do I modify it such that it will prevent scrolling in this way?
$('body').on({
'mousewheel': function(e) {
if (e.target.id == 'el') return;
e.preventDefault();
e.stopPropagation();
}
})
You can just have the window continue to scroll back to the element by using window.scrollTo.
I get the top bottom position and the height of the element, and then when the element is in view of the window I scollTo the difference between the window innerHeight and the elements position.
var el = document.querySelector('.stop');
window.addEventListener('scroll', function (e) {
var elementPos = el.getBoundingClientRect(),
elBot = elementPos.bottom,
elHeight = elementPos.height,
curTop = window.pageYOffset || document.documentElement.scrollTop;
if(elBot <= window.innerHeight-elHeight){
window.scrollTo(0,curTop-(window.innerHeight - elBot));
}
});
Live Demo
And a more complete example with clicking to move on, just to illustrate further.

Switch tabs based on mouse scroll

I would like to have a widget on a webpage containing a number of tabs. When the user scrolls the page and the widget comes in to view and he keeps scrolling down, the tabs should be activated one by one (without the page scrolling further down). Once the last tab is showing, the page should resume scrolling as usual. Is this doable using JS/jQuery?
UPDATE:
Since this seems too broad a question:
The problem is, I don't know how to use the scroll offset and prevent the page from scrolling down until I decide it can resume its normal behavior
UPDATE 2
I created This fiddle,
$(document).ready(function(){
$('#tabbed').mouseover(function(){
$(this).focus();
}).scroll(function(){
console.log("scrolling tabs");
});
$(window).scroll(function(evt){
var scrollPos = $(this).scrollTop()
console.log(scrollPos);
// BULLETPROOF WAY TO DETECT IF THE MOUSE IS OVER THE
// SCROLLABLE DIV AND GIVE IT FOCUS HERE?
});
});
it contains a long page and a scrollable div among its contents. The only problem is that the div starts catching scroll events only if I move my mouse. If I could find a bulletproof way to activate the scrolling div whenever the mouse is over it I'm there. Any ideas?
You can't prevent scrolling with javascript. Using iframes and divs with scroll will only work if the mouse is over them.
You can cancel the mouse wheel and keys events related to the scrolling, however the user will be able to scroll using the scrollbar (more here).
Another approach is leaving an empty area and fixing your widget inside this area, like in this working example
$(window).bind('scroll', function()
{
var scroll = $(window).scrollTop(),
innerHeight = window.innerHeight || $(window).height(),
fooScroll = $('#fooScroll'),
emptyArea = $('#emptyArea'),
offset = emptyArea.offset(),
fixedClass = 'fixed';
if(scroll > offset.top)
{
if(scroll < offset.top + emptyArea.height() - fooScroll.height())
{
fooScroll.addClass(fixedClass);
fooScroll.css("top", 0);
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", emptyArea.height() - fooScroll.height());
}
}
else
{
fooScroll.removeClass(fixedClass);
fooScroll.css("top", 0);
}
});
Then you can change the tabs while the page is scrolling.
You should be able to do this. You can use the jQuery scroll event to run your own code whenever the user scrolls up or down. Also, so long as you call e.preventDefault() whenever the scroll event is fired, you can prevent the whole window from scrolling up or down.

On scroll load data on demand

I am implementing on demand loading of data through scrolling.
I have register the function in document.ready for a div.
The data should only be populated once the scroll is reached to the last. so to identify whether the scroll has reached till the last i am using the below function.
$("#tree").scroll(function () {
if (isScrolledToBottom(this)) {
}
});
But the function is not returning the correct value. What I mean is it should return the a true value when scroll has reached to its last.
function isScrolledToBottom(object) {
return ($(object).attr('scrollHeight') - $(object).scrollTop() - 1) <= $(object).height();
};
Try this instead :
return ($(object).attr('offsetHeight') + $(object).attr('scrollTop') >= $(object).attr('scrollHeight'));
If you want to do infinite scrolling, check out my answer here:
How to load the web page content based on user scrolling
This demo is triggered at a certain Y scroll position. If you are looking to accomplish this specifically when a user reaches a certain item, you might want to look at the Waypoints plugin.
http://imakewebthings.com/jquery-waypoints/
Infinite scroll Demo: http://imakewebthings.com/jquery-waypoints/infinite-scroll/
$('.theItems:last').waypoint(function(event, direction) {
//Ajax fetch here
});
var scrollHeight = $(object).prop("scrollHeight"); // total scrollable height of the element
var scrollTop = $(object).scrollTop(); // how far you have come from the top while scrolling vertically
var height = $(object).height(); // the constant height of the portion in display at all times
if (scrollHeight === (scrollTop + height)) {
//console.log("fetching page");
fetchNextPage();
}

Categories