dan178
dan178

Reputation: 385

How to avoid creating several if/statements and/or instances of function

I have this code: https://pastebin.com/zgJdYhzN in Javascript. It's supposed to fade in text when the scrolling function reaches a certain point and while this does work, there will be several pages using it and I'd like to avoid having to create several instances of this function. It would be better if I could just create a function and for every element that had the ".split" class, this would act upon it.

//EXECUTES ONLY ONCE
function once(fn, context) { 
    var result;
    return function() { 
        if(fn) {
            result = fn.apply(context || this, arguments);
            fn = null;
        }
        return result;
    };
}
// Usage
var split1 = once(function() {
    fadeInText(".split1");
});
var pl = once(function() {
    fadeInText(".pl");
});
var pl1 = once(function() {
    fadeInText(".pl1");
});
var smallp = once(function() {
    fadeInText(".smallp");
});
var smallp1 = once(function() {
    fadeInText(".smallp1");
});
var smallp2 = once(function() {
    fadeInText(".smallp2");
});
var smallp3 = once(function() {
    fadeInText(".smallp3");
});
var head0 = once(function() {
    fadeInText(".head0");
});

$(window).scroll(function() {

  if( $(this).scrollTop() + $(window).height() > $(".split1").offset().top) {
      split1();
  }
    if( $(this).scrollTop() + $(window).height() > $(".pl").offset().top) {
      pl();
  }
    if( $(this).scrollTop() + $(window).height() > $(".pl1").offset().top) {
      pl1();
  }
    if( $(this).scrollTop() + $(window).height() > $(".smallp").offset().top) {
      smallp();
  }
    if( $(this).scrollTop() + $(window).height() > $(".smallp1").offset().top) {
      smallp1();
  }
    if( $(this).scrollTop() + $(window).height() > $(".smallp2").offset().top) {
      smallp2();
  }
    if( $(this).scrollTop() + $(window).height() > $(".smallp3").offset().top) {
      smallp3();
  }
    if( $(this).scrollTop() + $(window).height() > $(".head0").offset().top) {
      head0();
  }
});

Upvotes: 2

Views: 77

Answers (2)

pixelscript
pixelscript

Reputation: 392

Not sure if I'm missing why you need the once method. Is there a reason you couldn't do something like this:

var selectors = ['.one', '.two', '.three'];
var elements = {};
selectors.forEach(function(selector){
    elements[selector] = $(selector);
});

function elementOnScreen(selector) {
    if(!elements[selector]){
        return false;
    }
    return  $(window).scrollTop() + $(window).height() > elements[selector].offset().top
}

$(window).scroll(function() {
    selectors.forEach(function(selector) {
        if(elementOnScreen(selector)){
            fadeInText(selector);
            delete elements[selector];
        }
        if(Object.keys(elements).length === 0){
            $(window).off('scroll');
        }
    });
});

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138437

Just generate the functions for all elements using a loop:

 const handlers = [".split1", ".pl" /*...*/]
   .map(s => ({ el: $(s), show: once(() => fadeInText(s)) }));

$(window).scroll(function() {
  for(const {el, show} of handlers) {
    if( $(this).scrollTop() + $(window).height() > el.offset().top) 
       show();
  }
});

You could also generate the handlers for all elements of a class:

const handlers = $(".split").toArray()
   .map(s => ({ el: $(s), show: once(() => fadeInText(s)) }));

Upvotes: 0

Related Questions