When learning to determine whether an element is in a viewable area, we first learn the position and size values of some elements.

The location information and size of the element

Most of the attributes are corresponding, so I’m only going to write one.

  • ClientWidth: the width of the element’s content area plus the width of the left and right inner margins, i.e. clientWidth = Content + padding

  • OffsetTop, the pixel distance between the upper outer border of an element and the upper inner border of the containing element. // The offset of the element does not change as the scrollbar moves. And is computed relative to the location of the parent element. If there is no positioned parent, the distance to the window is obtained, calculated from the outer border of the element to the inner border of the parent

  • Document. The documentElement. ScrollHeight: to obtain the total height of the browser window. Includes the hidden height of the scroll bar. , if there is no scroll bar, then he is equal to the document. The documentElement. ClientWidth.

  • For the document. The documentElement. ClientWidth viewport width. Is the width of the browser window.

  • GetBoundingClientRect () returns the size of the element and its position relative to the viewport. The size obtained here includes the border, the content, and the inside margin. Gets the position relative to the viewport as the distance from the viewport to the outer border.

  • Document. The documentElement. ScrollTop: access to the height of the scroll bar rolling. This value can be set.

Knowing some of the properties above, we are ready to learn the first method of judgment

By the position of the element and the height of the scroll bar

function isContain(dom) {
    // Get the coverage of the visual window.
    const screenHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
    // Get the height of the scroll bar
    const scrollTop = document.documentElement.scrollTop;
    // Get the height of the element offset. It's the offset from the visible window.
    const offsetTop = dom.offsetTop;
    return offsetTop - scrollTop <= screenHeight;
}
Copy the code

Use the getBoundingClientRect method to get the element’s position and then determine it (something I haven’t seen before)

Let’s start with the getBoundingClientRect method.

It is a method on a DOM object. Return a DOMRect object. This object has left, top, right, bottom, x, y, width, and height attributes.

The top, left, right, and bottom properties change as the page scrolls.

Top: The distance from the top border of the element to the top of the viewport.

Left: The distance between the left border of the element and the left end of the viewport.

Bottom: The distance between the bottom border of the element and the top of the viewport.

Right: The distance from the element’s right border to the left of the viewport.

If you want to determine if a child element is in the viewable area, you just need to:

  • Top is greater than or equal to 0
  • Left is greater than or equal to 0
  • Bottom is less than or equal to the window height
  • Right is less than or equal to the window width
    function isContain(dom) {
      const totalHeight = window.innerHeight || document.documentElement.clientHeight;
      const totalWidth = window.innerWidth || document.documentElement.clientWidth;
      // The top, left, bottom, and right moments change as the scroll bar scrolls.
      const { top, right, bottom, left } = dom.getBoundingClientRect();
      return (top >= 0 && left >= 0 && right <= totalWidth && bottom <= totalHeight);
    }
Copy the code

Listener is implemented through webAPI, Intersection Observer.

For details, please refer to MDN: developer.mozilla.org/zh-CN/docs/…

The Intersection Observer API registers a callback function that is triggered whenever a monitored element enters or exits another element (or a viewPort), or when the size of the Intersection of two elements changes.

const options = {
    root: // Check the visibility of the target. Must be the ancestor node of the target element.
    rootMargin: "Top right, bottom left." // Set the margin for the ancestor node, which is equivalent to the margin in CSS. Use to expand or reduce the size of the 'rootBounds' rectangle to affect the size of the' intersectionRect 'intersection area.
    threshold: // The callback is triggered when the child and parent elements are covered.
}

const observer = new IntersectionObserver((entries) = > {
    // Do something when the condition is met
    // Here we determine whether entries[0]. IsIntersecting are in the visible area
}, options)

observer.observe(dom);
Copy the code

Here are three examples

In this example, the background color of the window is green if the child element is not displayed in the current window, and blue if not.

  <style>
    .div {
      height: 2000px;
    }

    p {
      height: 200px;
      background: red;
    }
  </style>
  
  <body>
  <div class="div"></div>

  <p id="p">I appeared!</p>
  
  <! -- Using the element position relation method -->
  <script>
    function isContain(dom) {
      // Get the coverage of the visual window.
      const screenHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      // Get the height of the scroll bar
      const scrollTop = document.documentElement.scrollTop;
      // Get the height of the element offset. It's the offset from the visible window.
      const offsetTop = dom.offsetTop;
      return offsetTop - scrollTop <= screenHeight;
    }
    const p = document.getElementById("p");
    window.onscroll = () = > {
      if (isContain(p)) {
        document.body.style.backgroundColor = 'blue'
      } else {
        document.body.style.backgroundColor = 'green'}}</script>

  <! GetBoundingClientRect -->
  <script>
    // True is returned only if all of the children are present in the parent element.
    function isContain(dom) {
      const totalHeight = window.innerHeight || document.documentElement.clientHeight;
      const totalWidth = window.innerWidth || document.documentElement.clientWidth;
      // The top, left, bottom, and right moments change as the scroll bar scrolls.
      const { top, right, bottom, left } = dom.getBoundingClientRect();
      console.log(top, right, bottom, left)
      return (top >= 0 && left >= 0 && right <= totalWidth && bottom <= totalHeight);
    }

    const p = document.getElementById("p");
    window.onscroll = () = > {
      if (isContain(p)) {
        document.body.style.backgroundColor = 'blue'
      } else {
        document.body.style.backgroundColor = 'green'}}</script> 
  
  <! -- Through New IntersectionObserver(); -->
  <script>
    const observer = new IntersectionObserver((entries) = > {
      if (entries[0].isIntersecting) {
        document.body.style.backgroundColor = "blue"
      } else {
        document.body.style.backgroundColor = "green"}}, {threshold: 2. });
    const p = document.getElementById("p")
    observer.observe(p)
  </script>
</body>
Copy the code