based on this thread I added a scroll up to next div, like this:
var f = jQuery('.p');
var nxt = f;
jQuery(".next").click(function() {
if (nxt.next('.scroller').length > 0) {
nxt = nxt.next('.scroller');
} else {
nxt = f;
}
jQuery('html,body').animate({
scrollTop: nxt.offset().top
},
'slow');
});
var f = jQuery('.p');
var prev = f;
jQuery(".previous").click(function() {
if (prev.prev('.scroller').length > 0) {
prev = prev.prev('.scroller');
} else {
prev = f;
}
jQuery('html,body').animate({
scrollTop: prev.offset().top
},
'slow');
});
So this scrolls up and down very nicely.
The problem though, is that when the user scrolls, the script doesn't notice it. That is, the user scrolls from div1 to div4, when the user click on my "next"-button, he or she gets scrolled to div2. How can I solve this?
I checked into this but I cannot combine it with the above. There must be an easier way, right?
Any help much appreciated!
Oh... I think I might have solved it myself like this:
var jQuerycurrentElement = jQuery(".scroller").first();
jQuery(".next").click(function () {
var jQuerynextElement = jQuerycurrentElement.next(".scroller");
// Check if next element actually exists
if(jQuerynextElement.length) {
// If yes, update:
// 1. $currentElement
// 2. Scroll position
jQuerycurrentElement = jQuerynextElement;
jQuery('html, body').stop(true).animate({
scrollTop: jQuerynextElement.offset().top
}, 100);
}
return false;
});
jQuery(".previous").click(function () {
var jQueryprevElement = jQuerycurrentElement.prev(".scroller");
// Check if previous element actually exists
if(jQueryprevElement.length) {
// If yes, update:
// 1. $currentElement
// 2. Scroll position
jQuerycurrentElement = jQueryprevElement;
jQuery('html, body').stop(true).animate({
scrollTop: jQueryprevElement.offset().top
}, 100);
}
return false;
});
The above is based on this.
The only problem here is that when parts of a div is scrolled into view, the next and previous buttons sometimes behave strange. For example, when being between div2 and div3 and div 3 is most visible, the previous click can take the user back to div1, which feels not so logical. Can we adjust this somehow? I suppose I would have to do something with the offset but I am unsure.
Related
I am working on a long one-pager. Yes, I know, we hate one-pagers. At least I promise not to implement any parallax-effect, I promise :)
I have multiple sections I can open/close. This part works fine.
The problem: those sections get pretty long, and when they are being closed/collapsed, the user find himself somewhere in the middle of the one-pager.
So, when collapsing a section, I want it to collapse AND to smooth scroll back to the top/the start of the collapsed section.
Here my script:
// Section-Collapse
//---------------------------------------------------------
$("section a.read-more").click(function() {
if($(this).parents("section").hasClass("expanded")) {
var scrollAnchor = $(this).attr("data-scroll"),
scrollPoint = $(".anchor[data-anchor='" + scrollAnchor + "']").offset().top - 0;
$("body,html").animate({
scrollTop: scrollPoint
}, 1500, function() {
// close/collapse section
$(this).parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
$(this).parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
});
} else {
// open section
$(this).parents("section").addClass("expanded");
$("section.expanded div.expandable-content").slideDown();
}
});
The problem: this part is not being executed EXCEPT the alert message, that one works. Although it is trying to open the dialog window multiple times and Firefox offers me to block this behavior.
// einklappen
$(this).parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
$(this).parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
It scrolls back to top, to the anchor, but the section will not collapse...
Any ideas why it won't collapse?
Regards,
Milan
---------------------------UPDATE
So, it was a problem with the scope of variable "this".
This code here seems to work fine:
// Section-Collapse
//---------------------------------------------------------
$("section a.read-more").click(function() {
if($(this).parents("section").hasClass("expanded")) {
var scrollAnchor = $(this).attr("data-scroll"),
scrollPoint = $(".anchor[data-anchor='" + scrollAnchor + "']").offset().top - 0;
var global_this = $(this);
$("body,html").animate({
scrollTop: scrollPoint
}, 1500, function() {
// einklappen
global_this.parents("section").addClass("close");
$("section.expanded.close div.expandable-content").slideUp();
global_this.parents("section").removeClass("expanded").removeClass("close");
alert("this test-message is being displayed");
});
// return false;
} else {
// ausklappen
$(this).parents("section").addClass("expanded");
$("section.expanded div.expandable-content").slideDown();
}
});
What is bothering me: why this script tries to open multiple alert dialogs?
I've put together an accordion script that works quite nicely (haven't cross-browser tested) and allows for lots of content inside each drawer to be accessed and visible on screen. A lot of times accordions open and cause issues with positioning after opening. Anyway, the code I'm using has a toggle active function and a scroll function being called on click.
function toggleActive(link){ // Set anchor to active
if ( $(link).hasClass("active") ) {
$(link).removeClass("active");
} else {
$(link).addClass("active");
};
};
function scrollToElement(selector, time, verticalOffset) { // param 1 = id, param 2 = speed
time = typeof(time) != 'undefined' ? time : 1000;
verticalOffset = typeof(verticalOffset) != 'undefined' ? verticalOffset : 0;
element = $(selector);
offset = element.offset();
offsetTop = offset.top + verticalOffset;
$('html, body').animate({scrollTop: offsetTop }, time);
}
$('#accordion a').click(function(e) {
var link = '#' + event.target.id
$(".tab-content").slideUp();
$(".tab").removeClass("active");
toggleActive(link);
$(link).next().slideToggle("fast");
setTimeout(function() {
scrollToElement($(link), 500);
}, 500);
e.preventDefault();
});
So when clicked, all of the tabs are closed and made inactive, then the targeted "drawer" is opened and made active. If for any reason you click an already "active" drawer, it runs through the script again. What I'd like to do is place an IF statement that determines if what you just clicked is already open, and then simply close that drawer. Thanks in advance. I don't know why this is causing me headaches.
JSFiddle
As I understand you need another function as below:
function isAlreadyActive(link)
{
if ( $(link).hasClass("active") ) {
$(link).removeClass("active");
return true;
} else {
return false;
};
}
And you should call that function in your click event. This function will check if the link already active, if so just deactivates it and changes as you want.
$('#accordion a').click(function(e) {
var link = '#' + event.target.id
/* if it is already active, just deactivate it and exit*/
if(isAlreadyActive(link)){
return false;
}
$(".tab-content").slideUp();
$(".tab").removeClass("active");
toggleActive(link);
$(link).next().slideToggle("fast");
setTimeout(function() {
scrollToElement($(link), 500);
}, 500);
e.preventDefault();
});
I hope this helps.
I'm hoping a Javascript wiz can help a fellow citizen out with resolving a problem. I've a fairly straight forward function. When I scroll down by 1px I would like to apply a bounceDown class, this will run for 5 seconds and the class will then disappear for future running of the same function.
When I scroll up from that current scroll position I would like the bounceUp effect to apply. However the issue is I think the bounceUp effect only works once you scroll past the original scroll but in addition to this if the previous function is still running on it's 5 second transition then it gets jumpy as it's trying to run two classes at the same time so there almost needs to be a delay applied.
Does anyone think they can help, I'd gratefully appreciate it.
<script>
(function($){
$.fn.extend({
addTemporaryClass: function(className, duration) {
var elements = this;
setTimeout(function() {
elements.removeClass(className);
}, duration);
return this.each(function() {
$(this).addClass(className);
});
}
});
})(jQuery);
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1) {
$(".spanner").addTemporaryClass("BounceDown", 5000);
}
else if (scroll <= 1) {
$(".spanner").addTemporaryClass("BounceUp", 5000);
}
});
</script>
What about a boolean variable that is 'true' when addTemporaryClass is running? So:
(function($){
var classAdded = false; //New
$.fn.extend({
addTemporaryClass: function(className, duration) {
classAdded = true; //New
var elements = this;
setTimeout(function() {
elements.removeClass(className);
classAdded = false; //New
}, duration);
return this.each(function() {
$(this).addClass(className);
});
}
});
})(jQuery);
$(window).scroll(function() {
var scroll = $(window).scrollTop();
if (scroll >= 1 /*New*/ && !classAdded /*New*/) {
$(".spanner").addTemporaryClass("BounceDown", 5000);
}
else if (scroll <= 1 /*New*/ && !classAdded /*New*/) {
$(".spanner").addTemporaryClass("BounceUp", 5000);
}
});
I am trying to create a website that automatically scrolls to each section upon a single scroll action. This means that the code has to check if the page is scrolled up or scrolled down. I believe the code below solves my problem but the scroll action is fired more than once while the page is scrolling. You will see that the first alert in the if statement reaches 5 instead of the desired 1. Any help on the matter would be highly appreciated.
[Note] I am using the velocity.js library to scroll to each section within the container.
var page = $("#content-container");
var home = $("#home-layer-bottom");
var musicians = $("#musicians");
var athletes = $("#athletes");
var politics = $("#politics");
var bio = $("#politics");
var pages = [ home,musicians,athletes,politics,bio ];
var pageCur = 0;
var lastScrollTop = 0;
page.scroll(function(){
var st = $(this).scrollTop();
var pageNex = pageCur + 1;
if (st > lastScrollTop){
alert(pageNex);
pages[pageNex].velocity("scroll", { container: $("#content-container") });
} else {
alert(pageCur-1);
pages[pageCur-1].velocity("scroll", { container: $("#content-container") });
}
lastScrollTop = st;
pageCur = pageNex;
});
The scroll event (as well as the resize event) fire multiple times as a user does this. To help this, the best practice is to debounce. However, I've never gotten that to work. Instead, I use a global boolean to check if the function has fired.
var scrolled = false;
page.on('scroll', function(){
if(!scrolled){
scrolled = true;
//do stuff that should take a while...
scrolled = false;
};
});
This worked for me!
var ScrollDebounce = true;
$('.class').on('scroll',
function () {
if (ScrollDebounce) {
ScrollDebounce = false;
//do stuff
setTimeout(function () { ScrollDebounce = true; }, 500);
}
})
I have this code and it works exactly as I want. The menu bar sits on top and recognizes the section it is on or in. You can click the links in the yellow menu to move between the sections.
http://jsfiddle.net/spadez/2atkZ/9/
http://jsfiddle.net/spadez/2atkZ/9/embedded/result/
$(function () {
var $select = $('#select');
var $window = $(window);
var isFixed = false;
var init = $select.length ? $select.offset().top : 0;
$window.scroll(function () {
var currentScrollTop = $window.scrollTop();
if (currentScrollTop > init && isFixed === false) {
isFixed = true;
$select.css({
top: 0,
position: 'fixed'
});
$('body').css('padding-top', $select.height());
} else if (currentScrollTop <= init) {
isFixed = false;
$select.css('position', 'relative');
$('#select span').removeClass('active');
$('body').css('padding-top', 0);
}
//active state in menu
$('.section').each(function(){
var eleDistance = $(this).offset().top;
if (currentScrollTop >= eleDistance-$select.outerHeight()) {
var makeActive = $(this).attr('id');
$('#select span').removeClass('active');
$('#select span.' + makeActive).addClass('active');
}
});
});
$(".nav").click(function (e) {
var divId = $(this).data('sec');
$('body').animate({
scrollTop: $(divId).offset().top - $select.height()
}, 500);
});
});
However, the code itself gets quite laggy as soon as you start putting any content in the boxes. I wondered if there is any opportunity to optimize the code and make it run a bit smoother.
The problem you have is that you're repeatedly changing page layout properties (via the animation) and querying page layout properties (in the scroll handler), thus triggering a large number of forced layouts.
If i understand your code correctly you could get a big improvement by disabling the scroll handler during the click animation and instead triggering the effects with no checks made (set the active class on the clicked element).