Can this jQueryJjavaScript snippet be re-written more efficiently? - javascript

I am trying to write this code more efficiently. I've tried about 25 different permutations and it only seems to break it.
Basically, I am adding various classes to elements to trigger a css/keyframes animation when the window width is 1025px or greater.
And then there is another class being adding when it is less than 1024px which is intended to reveal the element without the element.
<script type="text/javascript">
var width = $(window).width();
if(width >= 1025) {
$(window).scroll(function() {
$('#about .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideLeft"); }
});
$('#author .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideRight"); }
});
$('#feed .blog_01').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("oneUp"); }
});
$('#feed .blog_02').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("twoUp"); }
});
$('#feed .blog_03').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("thrUp"); }
});
$('#feed .more').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+1000) { $(this).addClass("moreUp"); }
});
});
}
else {
$('#about .image img.flex').addClass('visible');
$('#author .image img.flex').addClass('visible');
$('#feed .blog_01').addClass('visible');
$('#feed .blog_02').addClass('visible');
$('#feed .blog_03').addClass('visible');
$('#feed .more').addClass('visible');
}
</script>
EDIT
Maybe it would be better to visualize it like this:
Perhaps it would be better to say how can I make this portion more efficient...
var width = $(window).width();
if(width >= 1025) {
$(window).scroll(function() {
$('#about .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideLeft"); }
});
$('#author .image img.flex').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("slideRight"); }
});
$('#feed .blog_01').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("oneUp"); }
});
$('#feed .blog_02').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("twoUp"); }
});
$('#feed .blog_03').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+600) { $(this).addClass("thrUp"); }
});
$('#feed .more').each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
if (position < top+1000) { $(this).addClass("moreUp"); }
});'

#icicleking's answer looks pretty great, but if you need to preserve you addClasses, you could iterate over the important values.
DEMO
var width = $(window).width();
// Make an array of data objects
var data = [
{ el: '#about .image img.flex', plus: 600, newClass: "slideLeft" },
{ el: '#author .image img.flex', plus: 600, newClass: "slideRight" },
{ el: '#feed .blog_01', plus: 600, newClass: "oneUp" },
{ el: '#feed .blog_02', plus: 600, newClass: "twoUp" },
{ el: '#feed .blog_03', plus: 600, newClass: "thrUp" },
{ el: '#feed .more', plus: 1000, newClass: "moreUp" }
];
if(width >= 1025) {
$(window).scroll(function() {
// Loop over the array of data objects
data.forEach(function(d) {
// For each object, target the el attribute for more looping...
$(d.el).each(function() {
var position = $(this).offset().top;
var top = $(window).scrollTop();
// ...use the plus attribute in this condition...
if (position < (top + d.plus)) {
// ...and add the newClass attribute
$(this).addClass(d.newClass); }
});
});
});
} else {
data.forEach(function(d) {
$(d.el).addClass('visible');
});
}

Caveat, triggering animation directly on scroll events is not an efficient way of animating. Others have written much more than I can say about this. When you say "efficient", I'm assuming here that you mean shorter, easier to read.
You could try something like this, sorry I didn't transpose your classes.
$(window).scroll(function() {
var top = $(window).scrollTop();
$('.all, .the, .selectors, .belong, .to, .us').each(function(e) {
var position = $(this).offset().top;
if ($(this).hasClass('.all') && position < top+1000) {
$(this).addClass('.slideThisClass');
}
else if($(this).hasClass('.the') && position < top+600) {
$(this).addClass('.theOtherSlideClass');
}
// etc.
}
}

Related

Scrolling sidebar inside a div with scrollbar - $(window).on('scroll', function()?

I want my social sidebar make scroll only within the gray div. I have already put the sidebar within the gray div does not exceed the footer or the content above. My difficulty is to sidebar scroll accompanying the scroll without going gray div.
http://test.eae.pt/beautyacademy/angebot/
JS:
beautyAcademy.sharer = {
element: void 0,
elementToScroll: void 0,
init:function() {
this.element = $('.js-sharer-ref');
console.log(this.element.length);
if(this.element.length != 1) {
return;
}
this.build();
},
build: function() {
this.binds();
},
binds: function() {
var _this = this;
// Element that's gonna scroll
this.$elementToScroll = $('.fixed-social');
// Element that's gonna scroll height
this.elementToScrollHeight = this.$elementToScroll.outerHeight();
// Element where scroll is gonna happen Height
this.elementHeight = this.element.outerHeight();
// Element where scroll is gonna happen distance to top
this.elementOffsetTop = this.element.offset().top;
// Scroll that was done on the page
this.windowScrollTop = $(window).scrollTop();
this.elementOffsetBottom = this.elementOffsetTop + this.elementHeight - this.elementToScrollHeight;
this.$elementToScroll.css('top', (_this.elementOffsetTop+80) + "px");
$(window).on('scroll', function() {
if(this.windowScrollTop + this.elementToScrollHeight < this.elementHeight )
this.$elementToScroll.css('margin-top', this.windowScrollTop );
});
}
};
You need to try like below :
$(function(){
if ($('#container').length) {
var el = $('#container');
var stickyTop = $('#container').offset().top; // returns number
var stickyHeight = $('#container').height();
$(window).scroll(function(){ // scroll event
var limit = $('#footer').offset().top - stickyHeight - 20;
var windowTop = $(window).scrollTop(); // returns number
if (stickyTop < windowTop){
el.css({ position: 'fixed', top: 0 });
}
else {
el.css('position','static');
}
if (limit < windowTop) {
var diff = limit - windowTop;
el.css({top: diff});
}
});
}
});
DEMO

jQuery TopDistance animation start?

I have a little problem with the script that I wrote.
Well, for some reason, it not refers to TopDistance which is declared to 850. Just one clicked on the down arrow and the animation starts.
Can you help with this early boot animation?
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).addClass("animated fadeInRight");
}
});
});
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).removeClass("projekt");
}
});
});
Take a look at this jsfiddle.
I've made one function instead of two and it works.
$(window).on('scroll', function () {
var scrollTop = $(this).scrollTop();
$('.projekt').each(function () {
var topDistance = $(this).offset().top;
if ((topDistance - 850) < scrollTop) {
$(this).addClass("animated fadeInRight").removeClass('projekt');
}
});
});

How to find Multiple div reach top?

I have a survey page divided into sections. As the user scrolls, each section's header sticks to the top of the screen until the next section is reached. I was able to do it for the first and second section but I am not sure how to do it for the third one. There must be a better way to do this.
Here is my code and a jsfiddle
Thank you
var s = $("#block2 .question-title-block");
var pos = s.position();
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
if ($(this).scrollTop() > 404) {
$('#block1 .question-title-block').addClass("sticky");
if (windowpos >= pos.top) {
$('#block2 .question-title-block').addClass("sticky");
$('#block1 .question-title-block').removeClass("sticky");
}
else{
$('#block2 .question-title-block').removeClass("sticky");
}
}
else{
$('#block1 .question-title-block').removeClass("sticky");
$('#block2 .question-title-block').removeClass("sticky");
}
})
If you want it to be applied to as many elements as you want, don't use them individually, use their class. Here is what you can do:
var titleBlocks = $(".question-title-block");
$(window).scroll(function() {
var windowpos = $(window).scrollTop();
titleBlocks.each(function(){
$(this).toggleClass('sticky', $(this).parent().offset().top <= windowpos);
});
});
JS Fiddle Demo
try this (allows for any number of question blocks):
var containers = $('.question-block-container');
$(window).scroll(function () {
var windowpos = $(window).scrollTop();
containers.each(function () {
var container = $(this),
title = container.find('.question-title'),
contOffsetTop = container.offset().top,
conOffsetBottom = contOffsetTop + container.outerHeight() + 60; // 60 is margin bottom
if (windowpos >= contOffsetTop && windowpos <= conOffsetBottom) {
if (!title.hasClass("sticky")) {
title.addClass("sticky");
}
} else if (title.hasClass("sticky")) {
title.removeClass("sticky");
}
});
});
Example

Simplify functions so this does not get too big

I have this code so that each element make the scroll effect when done: I keep repeating the function to each element, the problem that are 8 elements with different classes to add functions, the code would be very large.
$(window).scroll(function () {
$('#section6').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 200) {
svgEstatua.start();
}
});
});
$(window).scroll(function () {
$('#section2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 225) {
svgBrain.start();
}
});
});
// must 5
array:
var groupSvg = [svgManos, svgSuper, svgInnovation, svgEstatua, svgBrain, svgBalanza];
Take out the common code and do something like this
function common(selector, svgObject, offset) {
$(selector).each(function () {
var imagePos = $(this).offset().top,
topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + offset) {
svgObject.start();
}
});
}
$(window).scroll(function () {
common('#section6', svgEstatua, 200);
});
$(window).scroll(function () {
common('#section2', svgBrain, 225);
});
You can then use your array or an object to loop though.

Simplify functions so the code does not get too big

I have this code so that each element make the scroll effect when done:
I keep repeating the function to each element, the problem that are 30 elements with different classes to add, the code would be very large.
jQuery:
$(window).scroll(function () {
$('.regalos').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("stretchLeft");
}
});
$('.sprite-Layer-2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("slideLeft");
}
});
// ... must 28
});
I would use:
$(window).scroll(function () {
var topOfWindow = $(window).scrollTop();
function _checkOffset(className) {
return function () {
var $this = $(this),
imagePos = $this.offset().top;
$this.toggleClass(className, (imagePos < topOfWindow + 400));
};
}
$('.regalos').each(_checkOffset('stretchLeft'));
$('.sprite-Layer-2').each(_checkOffset('slideLeft'));
});
However, you might be better off re-thinking your structure to avoid adding different class names based on the offset.
You could create a HashMap of Key/Value pairs (key = ID / Class, value = your string inside of .addClass()). However, this would only work if you only had a single class that you wanted to add via addClass for each key that you had.
Or you could have a complex HashMap, where the value was a an array, that you further iterated through if you really wanted to....
You can use something like this, as a global function and you pass array via the items.
var fn = function(args) {
for (var i = 0; i < args.elements.length; i++) {
var el = args.elements[i];
$(el).each(function() {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass(args.cls);
}
});
}
};
$(window).scroll(function() {
fn({
elements: ['.regalos', '.sprite-layer-2']
cls: 'stretchLeft'
});
});
1st, create the function once:
var myfunction = function(that, whichway) {
var imagePos = $(that).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(that).addClass(whichway); }
};
Then call it as often as you'd like:
$('.regalos').each(myfunction(this, 'stretchLeft'));
$('.sprite-layer-2').each(myfunction(this, 'slideLeft'));
You can pass a list of classes to the jQuery selector.
$(window).scroll(function () {
$('.regalos, .sprite-Layer-2').each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass("stretchLeft");
}
});
});
But, I would add one class to all the elements and access them by that.
How about the following, where the key in the rules object is the class to add and the value is the selector for the items to get the class:
var rules = {
"slideLeft": ".sprite-Layer-2",
"stretchLeft": ".regalos",
"someOtherClass" : ".abc, .def, .ghi" // Multiple elements get this class
};
$(window).scroll(function () {
$.each(rules, function( className, selector) {
$(selector).each(function () {
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow + 400) {
$(this).addClass(className);
}
});
});
});
try the code below:
$(window).scroll(function () {
var topOfWindow = $(window).scrollTop();
$('.regalos').each(function () {
foo(this, 'stretchLeft');
});
$('.sprite-Layer-2').each(function () {
foo(this, 'slideleft');
});
});
function foo(that, classToBeAdded){
var imagePos = $(that).offset().top;
if (imagePos < topOfWindow + 400) {
$(that).addClass(classToBeAdded);
}
}

Categories

Resources