Scroll to next section - javascript

My code looks like this:
<div id="arrow">
<a class="next"></a>
<a class="previous"></a>
</div>
<section id="first">
...
</section>
<section id="second">
...
</section>
<section id="third">
...
</section>
The element #arrow has position: fixed, and I'm trying to make the window scroll to the next section when a.next is clicked.
Ex: The first time a.next is clicked, the window scrolls to section#first, the second time, the window scrolls to section#second, etc. The same thing happens to a.previous.
Does someone know how to solve this problem?
Thanks a lot!
EDIT
My JS code:
$('#arrows a.previous').click(function() {
$.scrollTo($(this).closest('section').prev(),800);
});
$('#arrows a.next').click(function() {
$.scrollTo($(this).closest('section').next(),800);
});

You will need to handle to 3 events in this case:
Current page position - updated each time.
User scrolls manualy the page.
User clicks the prev or next button.
2, 3 need to use the current page position and update him according to the direction that the page is scrolling.
My quick demos : Vertical Version jsFiddle --- Horizontal Version jsFiddle
Vertical Version snippet :
$(function(){
var pagePositon = 0,
sectionsSeclector = 'section',
$scrollItems = $(sectionsSeclector),
offsetTolorence = 30,
pageMaxPosition = $scrollItems.length - 1;
//Map the sections:
$scrollItems.each(function(index,ele) { $(ele).attr("debog",index).data("pos",index); });
// Bind to scroll
$(window).bind('scroll',upPos);
//Move on click:
$('#arrow a').click(function(e){
if ($(this).hasClass('next') && pagePositon+1 <= pageMaxPosition) {
pagePositon++;
$('html, body').stop().animate({
scrollTop: $scrollItems.eq(pagePositon).offset().top
}, 300);
}
if ($(this).hasClass('previous') && pagePositon-1 >= 0) {
pagePositon--;
$('html, body').stop().animate({
scrollTop: $scrollItems.eq(pagePositon).offset().top
}, 300);
return false;
}
});
//Update position func:
function upPos(){
var fromTop = $(this).scrollTop();
var $cur = null;
$scrollItems.each(function(index,ele){
if ($(ele).offset().top < fromTop + offsetTolorence) $cur = $(ele);
});
if ($cur != null && pagePositon != $cur.data('pos')) {
pagePositon = $cur.data('pos');
}
}
});
section { min-height:800px; }
#arrow {
position:fixed;
right:0;
top:0;
background-color:black;
color:white;
}
#arrow a{
display:inline-block;
padding:10px 20px;
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<div id="arrow">
<a class="next">next</a>
<a class="previous">prev</a>
</div>
<section style="background-color:green">...</section>
<section style="background-color:blue">...</section>
<section style="background-color:red">...</section>

All you need, to allow the user to use both arrows and scrollbar:
var $sec = $("section");
$(".prev, .next").click(function(){
var y = $sec.filter(function(i, el) {
return el.getBoundingClientRect().bottom > 0;
})[$(this).hasClass("next")?"next":"prev"]("section").offset().top;
$("html, body").stop().animate({scrollTop: y});
});
*{margin:0;padding:0;}
#arrow{
position:fixed;
width:100%;
text-align:center;
}
#arrow a{
display:inline-block;
background: tomato;
padding:6px 15px;
border-radius:3px;
cursor:pointer;
}
section{
height:1200px;
border:3px solid #444;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="arrow"><a class="prev">↑</a><a class="next">↓</a></div>
<section>1</section>
<section style="height:500px;">2</section>
<section>3</section>
<section style="height:600px;">4</section>
<section>5</section>
To explain the jQuery a bit:
// Cache your selectors
var $sec = $("section");
// On any of both arrows click
$(".prev, .next").click(function(){
// We need to get current element
// before defining the `.next()` or `.prev()` element to target
// and get it's `offset().top` into an `y` variable we'll animate to.
// A current element is always the one which bottom position
// (relative to the browser top) is higher than 0.
var y = $sec.filter(function(i, el) {
return el.getBoundingClientRect().bottom > 0;
})[$(this).hasClass("next")?"next":"prev"]("section").offset().top;
// (Line above:) if the clicked button className was `"next"`,
// target the the `.next("section")`, else target the `.prev("section")`
// and retrieve it's `.offset().top`
$("html, body").stop().animate({scrollTop: y});
});

i have tried to do with .closest("section") but it only works when the section is a parent of the element you clicked so this is the best way i got
sections=$("section");
s=0;
$(".next").click(function() {
if(s<sections.length-1){
s++;
$('html, body').animate({
scrollTop: sections.eq(s).offset().top
}, 500);
}});
$(".previous").click(function() {
if(s>0){
s--;
$('html, body').animate({
scrollTop: sections.eq(s).offset().top
}, 500);
}});
section{
background-color:#bbb;
width:100%;
height:700px;
border-bottom:2px solid #eee;
}
#arrow{
position:fixed;
}
#first{
background-color: red;
}
#second{
background-color:green;
}
#third{
background-color: blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="arrow">
<a class="next">next</a>
<a class="previous">prev</a>
</div>
<section id="first">
...
</section>
<section id="second">
...
</section>
<section id="third">
...
</section>

Related

Previous and next buttons that navigate through a single page

Still a noob but I am slowly getting there.
I have a series of divs, all the same class and I have previous and next buttons that scroll to the top of the next or previous div when clicked. I would like to set an offset so that my header won't hide the div that scrolls underneath of it and I am unsure how to go about this. Code below.
<button class="prev link js-prev js-scroll-to">Previous</button>
<button class="next link js-next">Next</button>
<script>
$('.js-scroll-to').click(function(e) {
target = $($(this).attr('href'));
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-next').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(next);
$(selected).removeClass("js-current-panel");
$(next).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-prev').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(prev);
$(selected).removeClass("js-current-panel");
$(prev).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
</script>
For your case, I think you could just add the offset right into your animated scroll code (subtracting the height of the nav bar plus a little margin):
$('html, body').animate({scrollTop: target.offset().top - 54 + 'px'}, 1000);
I usually do this without a JS scroll by adding a span class to use as the anchor instead of anchoring on the div itself. This will work if someone links directly to the anchor point as well.
That way I can use position relative on the anchor to set an offset for the height of the nav bar.
In this case, I think you probably have some divs like this:
<div class="js-list-item js-current-panel">
content
</div>
<div class="js-list-item">
content
</div>
<div class="js-list-item">
content
</div>
I'd change it to:
<span class="anchor js-list-item js-current-panel"></span>
<div class="content">
content
</div>
<span class="anchor js-list-item"></span>
<div class="content">
content
</div>
<span class="anchor js-list-item"></span>
<div class="content">
content
</div>
With some CSS to position those new anchors (top depends on nav bar height):
.anchor {
position: relative;
top: -54px;
}
Example with some extra CSS to show how the anchors are positioned:
<style type="text/css">
.nav {
position: fixed;
top: 0;
left: 0;
right: 0;
width: 100%;
height: 44px;
background: black;
}
.main {
margin-top: 54px;
}
.js-list-item {
display: inline-block;
width: 5px;
height: 5px;
background: blue;
position: relative;
top: -54px;
}
.content {
background: red;
width: 100%;
height: 500px;
margin-bottom: 25px;
}
</style>
<div class="nav">
<button class="prev link js-prev js-scroll-to">Previous</button>
<button class="next link js-next">Next</button>
</div>
<div class="main">
<span class="js-list-item js-current-panel"></span>
<div id="one" class="content">content</div>
<span class="js-list-item"></span>
<div id="two" class="content">content</div>
<span class="js-list-item"></span>
<div id="three" class="content">content</div>
<span class="js-list-item"></span>
<div id="four" class="content">content</div>
<span class="js-list-item"></span>
<div id="five" class="content">content</div>
<span class="js-list-item"></span>
<div id="six" class="content">content</div>
<span class="js-list-item"></span>
<div id="seven" class="content">content</div>
</div>
<script src="https://code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script>
$('.js-scroll-to').click(function(e) {
target = $($(this).attr('href'));
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-next').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(next);
$(selected).removeClass("js-current-panel");
$(next).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
$('.js-prev').click(function(e) {
var selected = $(".js-list-item.js-current-panel");
var anchors = $(".js-list-item");
var pos = anchors.index(selected);
var next = anchors.get(pos+1);
var prev = anchors.get(pos-1);
target = $(prev);
$(selected).removeClass("js-current-panel");
$(prev).addClass("js-current-panel");
if (target.offset()) {
$('html, body').animate({scrollTop: target.offset().top + 'px'}, 1000);
}
e.preventDefault();
});
</script>

jQuery - element crossing another element

I have a fixed div on the page which contains a logo and as the user scrolls and this logo passes over other divs I wnat to the change the colour of the logo.
I have this working over a single div but need to it work across multiple so any help appreciated.
The WIP site can be seen here... dd.mintfresh.co.uk - if you scroll down you'll (hopefully) see the logo change from black to white as it crosses an illustrated egg. I need the same to happen when it crosses other divs further down the page.
The script so far...
jQuery(window).scroll(function(){
var fixed = jQuery("logo");
var fixed_position = jQuery("#logo").offset().top;
var fixed_height = jQuery("#logo").height();
var toCross_position = jQuery("#egg").offset().top;
var toCross_height = jQuery("#egg").height();
if (fixed_position + fixed_height < toCross_position) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else if (fixed_position > toCross_position + toCross_height) {
jQuery("#logo img").css({filter : "invert(100%)"});
} else {
jQuery("#logo img").css({filter : "invert(0%)"});
}
}
);
Any help appreciated. Thanks!
you need to fire a div scroll event. you can assign
$("div1").scroll(function(){
//change the color of the div1
}
});
$("div2").scroll(function(){
//change the color of the div2
}
});
or you can assign a class to divs which you want to change the color
$(".div").scroll(function(){
//change the color of the div which you are scrolling now
}
});
You can use like this :-
$(window).scroll(function() {
var that = $(this);
$('.section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('active')) {
$('.logo').addClass('invert');
} else {
$('.logo').removeClass('invert');
}
}
});
});
body {
padding: 0;
margin: 0;
}
div {
background: #f00;
height: 400px;
}
.logo {
position: fixed;
top: 0;
left: 0;
width: 100px;
}
.logo.invert {
filter: invert(100%);
}
div:nth-child(even) {
background: #ff0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<img src="https://dd.mintfresh.co.uk/wp-content/uploads/2018/06/DD_logo.svg" class="logo" />
<div id="page1" class="section"></div>
<div id="page2" class="section active"></div>
<div id="page3" class="section"></div>
<div id="page4" class="section active"></div>
<div id="page5" class="section"></div>
As your site code you can do like this :
$(window).scroll(function() {
var that = $(this);
$('#content > section').each(function() {
var s = $(this);
if (that.scrollTop() >= s.position().top) {
if(s.hasClass('black')) {
$('#logo img').css({filter: 'invert(0%)'});
} else {
$('#logo img').css({filter: 'invert(100%)'});
}
}
});
});

How to execute a function when the scroll reaches an element?

I want to hide all elements but the first one so I use $(".item:not(:eq(0))").fadeOut();
I have elements with the same class "item":
<div class="item">First Item</div>
<div class="item">Second Item</div>
<div class="item">Third Item</div>
<div class="item">Fourth Item</div>
Then when I scroll to the next element which could be "second , third,fourth item" , I want to show it
I tried using :
function isScrolledIntoView(elem)
{
var centerY = Math.max(0,((jQuery(window).height()-
jQuery(elem).outerHeight()) / 2)
+ jQuery(window).scrollTop());
var elementTop = jQuery(elem).offset().top;
var elementBottom = elementTop + jQuery(elem).height();
return elementTop <= centerY && elementBottom >= centerY;
}
jQuery(window).on("scroll resize", function() {
jQuery(".news:not(:eq(0))").each(function(index, element) {
if (isScrolledIntoView(element)) {
jQuery(element).fadeIn(10000);
}
});
});
But it doesn't work with my method because the height of the body changes on showing the next item "Second Item" , So All the items are shown when I scroll to the "Second Item" or any other item.
How to hide the items but the first one and then fadIn() each on scrolling to it ?
This is using offset() in jquery. This demo will trigger function if
your element is completely in your viewport.
Tip:You need to take care of inner as well as outer height of element.
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<style>
body{
height:200vh;
}
#test {
top: 100vh;
padding: 10px;
width: 300px;
position: relative;
border: 1px solid black;
height:100;
}
</style>
</head>
<body>
<p>scroll to test</p>
<div id="test">
<p>Click the button to get offsetTop for the test div.</p>
</div>
<script>
$(document).ready(function(){
$(window).scroll(function(){
var x = $("#test").offset();
var height1 = $("#test").outerHeight();
var y = document.documentElement.scrollTop;
var z = (x.top + height1) - y;
if(z < $(window).height()){
alert("fumction");
}
});
});
</script>
</body>
</html>
It will be more easy to use the combination of waypoint.js and animate.css.
Add animated class to every element to be animated. You can use any of the animate.css effects.
Change the offset { offset: '80%' } to control when the animation can start.
<div class="animated waypoint-slideup">
</div>
$('.waypoint-slideup').waypoint(function () {
$(this).addClass('slideInUp');
}, { offset: '80%' });
Use this in the css file
.waypoint-slideup{
opacity:0;}
.waypoint-slideup.slideInUp{
opacity:1;}

How to scroll from waypoint to waypoint in jQuery?

In my webpage I have 4 "waypoints" that have their respective links in a menu. What I need is to also bind the scroll of the page to these waypoints. So when the page loads, the pointer is at the top and based on the scrolling direction, the page moves to the next/previous waypoint. Until now I have come up with this simplistic approach, which goes into a scroll loop due to the scrollTo() function triggering the whole method again.
$(function () {
var top = $(window).scrollTop();
var currentWaypoint = 0;
var previousWaypoint = 0;
$(window).scroll(function () {
console.log("Scroll triggered");
console.log("Current Waypoint: " + currentWaypoint);
var curTop = $(window).scrollTop();
if (top < curTop) {
if (currentWaypoint < 4) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint+1;
}
}
else {
if (currentWaypoint > 0) {
previousWaypoint = currentWaypoint;
currentWaypoint=currentWaypoint-1;
}
}
top = curTop;
if (previousWaypoint != currentWaypoint) {
switch (currentWaypoint) {
case 1:
$.scrollTo(document.getElementById("waypoint-collection"));
case 2:
$.scrollTo(document.getElementById("waypoint-report"));
case 3:
$.scrollTo(document.getElementById("waypoint-video"));
case 4:
$.scrollTo(document.getElementById("waypoint-mail"));
default:
}
}
console.log("New Waypoint: " + currentWaypoint);
});
});
I've seen this sort of behaviour implemented in some websites but cannot seem to find anything relevant with google. Any ideas?
EDIT:
The relevant HTML code:
<html>
<head>
<style>
body {
background-color: #FFFFFF;
}
.features-container-wh {
min-height: 12.5rem;
text-align: center;
height: 100%;
}
.features-container-bl {
background-color: #43bfcb;
text-align: center;
color: #FFFFFF;
height: 100%;
}
.features-container-bottom {
height: 100%;
}
</style>
</head>
<body>
<div class="features-container-wh">
Collection
Report
Video
Mail
</div>
<div class="features-container-bl" id="waypoint-collection">
<p>Stuff...</p>
</div>
<div class="features-container-wh" id="waypoint-report">
<p>Stuff...</p>
</div>
<div class="features-container-bl" id="waypoint-video">
<p>Stuff...</p>
</div>
<div class="features-container-bottom" id="waypoint-mail">
<p>Stuff...</p>
</div>
</body>
$('html, body').animate({scrollTop: $("#.wayPoint1").offset().top}, 2000);

$('#div').bind('scroll' function({})) not working

I have added 2 codes here the window.scroll works on my example but not the second one binding the div to the scroll.
Any one knows what am I doing wrong!?
Just so you know I'm working in MeteorJS <- I dont think that this is the problem bc. the window scrolling works.
This 2 codes are in the same js file.
$(window).scroll(function() {
lastSession = Session.get('c_info')[Session.get('c_info').current]
if(lastSession.list == 0 && $(window).height() + $(window).scrollTop() >= $(document).height()){
lastItem = $( ".list-item div:last" ).html();
if (lastSession.page == 1){
currentSession().more();
lastItem2 = $( ".list-item div:last" ).html();
} else if( lastItem2 != lastItem) {
currentSession().more();
lastItem2 = $( ".list-item div:last" ).html()
}
}
});
$('#playlist').bind('scroll',function() {
console.log("div is scrolling");
});
I tried this too:
$('#playlist').scroll(function() {
console.log("div is scrolling");
});
MeteorJS Template:
<template name="playList">
<div id="playlist" class="playlist show-for-large-up">
{{#each list}}
<a href="/video/{{_id}}" class="large-12 columns" id="pl{{v_id}}">
<div>
<div class="large-7 columns plRight">
<span>{{vTitle}}</span>
</div>
</div>
</a>
{{/each}}
</div>
</template>
Also Tried:
$('#playlist').on('scroll',function() {console.log('test')});// not working
Tried to Change the id name and putting on the document ready:
$( document ).ready(function (){
$('#pl_list').bind('scroll',function() {
console.log("div is scrolling");
});
})//failed
The div has a scrollbar and the list is long and i have a css like this:
.playlist {
padding: 0;
overflow-y: scroll;
height: 458px;
}
Also tried:
Template.playList.rendered = function () {
console.log("playlist rendered");// i can see this on logs this tells that template is in doom
Meteor.setTimeout(function(){
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
}, 2000);// with settimeout i have giveng it 2 more seconds
}
Try this out -
$(document).ready(function(){
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
});
Use
$('#playlist').scroll(function() {
console.log("div is scrolling");
});
instead (like you did for window).
Thats the purpose of scroll(). See jquery documentation.
Scrolling event is fired on the element, if it has scrolled. So if you only scrolling the "body" element of the DOM it will not be triggered for #playlist.
So you have put a scrollbar to the container element of #playlist. Shot answer, cut the height and add a scrollbar, then the event will fire on it.
I did a Jsfiddle http://jsfiddle.net/34j0qnpg/4/
html
<div id="playlist-wrapper">
<div id="playlist" class="playlist show-for-large-up">
<a href="/video/1" class="large-12 columns" id="pl1">
<div>
<div class="large-7 columns plRight">
<span>Titel</span>
</div>
</div>
</a>
css part
body, html {
padding: 0;
margin: 0;
background-color: lightgrey;
color: #fff;
font-family: Arial;
height: 5000px;
overflow-y:scroll;
}
#stats {
position: relative;
}
#playlist-wrapper {
border: 1px solid #000;
padding: 10px;
height: 300px;
overflow-y: scroll;
}
#playlist {
height: 1000px;
background-color: darkgrey;
}
var $stats = $('#stats');
$('#playlist-wrapper').on('scroll', function() {
$stats.html('playlist scrolling');
console.log('playlist scrolling');
});
$(window).on('scroll', function() {
$stats.html('window scrolling');
console.log('window scrolling');
});
Solved with this code:
Tried it earlyer no results, after meteorjs project reset it just automagicly workded:
Template.playList.rendered = function () {
console.log("playlist rendered");
$('#playlist').on('scroll',function(){
console.log('Scrolling...');
});
}
I answered my question just if anybody is searching for the same answer.
Thanks to anybody who tried to help me.
I LOVE THIS COMMUNITY.

Categories

Resources