-2

I want to add a event to HTML element when it becomes on the user screen using only Javascript or React components but not jQuery.

I'm using react components and I want to run setInterval() function to make a simple counter using state, but the problem is the code runs when page is rendered, I want to start code only when the element becomes on the screen.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129

3 Answers3

1

I don't think you can accomplish this by adding an event to the element itself. I think you'll have to add listeners to the window for any events that can possibly change which elements are in view (load, scroll, resize).

I borrowed isScrolledIntoView() from this answer

// Get your element however you'd like
let myElmement = document.getElementById('myElement');
// Loop through possible events that will bring element into view
['resize','scroll','load'].forEach( eventName => {
  window.addEventListener(eventName, event => {
    if (isScrolledIntoView(myElmement)) {
      doYourThing();
    } else {
      console.log('nope');
    }
  });
});

// Borrowed from https://stackoverflow.com/a/22480938/12771340
function isScrolledIntoView(el) {
  let rect = el.getBoundingClientRect();
  let elemTop = rect.top;
  let elemBottom = rect.bottom;

  // Only completely visible elements return true:
  let isVisible = (elemTop >= 0) && (elemBottom <= window.innerHeight);
  // Partially visible elements return true:
  //isVisible = elemTop < window.innerHeight && elemBottom >= 0;
  return isVisible;
}
0
function isUserCanSeeIt(elemClassName,elemNumber){
    var elem = document.getElementsByClassName(elemClassName)[elemNumber];
    var elemPos = elem.getBoundingClientRect();
    if(elemPos.top > 0){
        return true;
    }
    else return false;
}
function event(elemClassName,elemNumber){
    if(isUserCanSeeIt(elemClassName)){
        doSomething();
    }
}
event("someClassName",0);
0

Use an intersection observer and set the interval within the callback:

let isIntersected = false;

const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    let count = 0;
    if (entry.intersectionRatio > 0 && !isIntersected) {
      isIntersected = true;
      setInterval(() => {
        document.querySelector("#counter").innerText = count;
        count++;
      }, 1000);
    }
  });
});

observer.observe(document.querySelector('.counter-container'))

A not very optimized example:

jsfiddle

eMontielG
  • 396
  • 1
  • 7