Using "cross-observer" as a baby, it is easy to realize lazy loading, top suction and bottom touching.

Keywords: Javascript Attribute network less IE

Let's first look at the introduction in MDN:

The Intersection Observer interface provides an asynchronous way to observe the intersection state of the target element with its ancestor element or top-level document viewport, which is called root.

Directly into the topic, Intersection Observer translates as "cross-observer". Its task is to monitor whether the target element and the specified parent element (user-specified, default is viewport) are cross-acting. Simple understanding is to monitor whether the target element enters or leaves the inside of the specified parent element (understand this sentence). I seem to be driving, but you don't have any evidence.

The following target elements are abbreviated as target, designated parent elements are abbreviated as father, crossover behavior is abbreviated as crossover, and viewport is abbreviated as window (vi)

There will be a motion picture below. First, bear with it! ____________

usage

1. Constructor

new IntersectionObserver(callback, options);

2. callback

A cross callback occurs, accepts an entries parameter, returns the set of targets that are currently monitored and crossed (an example of why "and crossed" occurs later):

new IntersectionObserver(entries => {
  entries.forEach(item => console.log(item));
  // ...
});

Let's see what common attributes are included in item:

attribute Explain
boundingClientRect spatial information
intersectionRatio Proportion of visible regions of elements
isIntersecting It is literally understood as crossing and can be used to determine whether an element is visible or not.
target Target node, just like event.target

Note: The page initialization triggers a callback, entries for all monitored target sets

3. options

As the name implies, it is a configuration parameter, object type, not required to fill in, common attributes are as follows:

attribute Explain
root Specify parent element, default window
rootMargin The offset value triggering crossover is "0px 0px 0px 0px 0px 0px 0px" by default (upper left and lower right, positive number diffuses outward, negative number shrinks inward)
new IntersectionObserver(callback, {
  root: document.querySelector("xx"),
  rootMargin: "0px 0px -100px 0px"
});

If rootMargin is set to "20px 0px 30px 30px 30px", then the element is switched to visible state before reaching the window:

4. Common methods

Name Explain parameter
observe Start listening for a target element node
unobserve Stop listening on a target element node
takeRecords Returns a collection of all monitored target elements
disconnect Stop all listening

Example

1. Suppose there is a class="box" box on the page and the parent element is a window:

let box = document.querySelector(".box");

let observer = new IntersectionObserver(entries => {
  entries.forEach(item => {
    let tips = item.isIntersecting ? "Into the interior of the parent element" : "Out of the parent element's interior";
    console.log(tips);
  });
});

observer.observe(box); // Listen on a box

The results are as follows:

2. Suppose there are several boxes with class="box" on the page and the parent element is a window:

let box = document.querySelectorAll(".box");

let observer = new IntersectionObserver(entries => console.log(`Cross-over behavior occurs, and the target elements are ${entries.length}individual`));

box.forEach(item => observer.observe(item)); // Listening for multiple box es

When all boxes are the same distance from the top of the window, the effect is as follows:

When all boxes are different from the top of the window, the effect is as follows:

Why do we take the above two cases for example, because entries are returning to the target set that has been monitored and crossed. In the first case, everyone crosses together, and the length of the set returned each time is three. In the second case, each target crosses in turn, and only one triggers at present. The length of the collection returned each time is only 1.

3. Specify the parent element

Suppose html is as follows:

<div class="parent">
  <div class="child"></div>
</div>

Then begin listening:

let child = document.querySelector(".child");

let observer = new IntersectionObserver(entries => {
  entries.forEach(item => {
    console.log(item.isIntersecting ? "So" : "Invisible");
  });
}, {
  root: document.querySelector(".parent")
});

observer.observe(child); // Start listening on child ren

The results are as follows:

practical application

1. Lazy loading of pictures

In the past, it used to listen to the browser scroll, then traverse to get the spatial information of each picture, and then judge some location information to load the picture; now it only needs to be handed to the cross-observer to do:

let images = document.querySelectorAll("img.lazyload");

let observer = new IntersectionObserver(entries => {
  entries.forEach(item => {
    if (item.isIntersecting) {
      item.target.src = item.target.dataset.origin; // Start loading pictures
      observer.unobserve(item.target); // Stop listening for images that have started loading
    }
  });
});

images.forEach(item => observer.observe(item));

The results are as follows:

Slow down the speed of the network:

Set the root Margin offset value to "0px 0px-100px 0px" (bottom shrinks inward):

Another advantage of this method is that when there is a horizontal scrollbar at a node on the page, it can handle it freely as follows:

Traditional lazy loading only monitors the scroll of global scrollbars, and such small details can not be achieved (the traditional method is not to determine whether the target appears in the window, so the horizontal images will be loaded together, even if you do not slide to the left), so this is also a major advantage of cross-observers.

2. Bottom Touch

We put a reference element at the bottom of the list and let the cross-observer listen.

Assume that the html structure is as follows:

<!-- Data List -->
<ul>
  <li>index</li>
</ul>

<!-- Reference element -->
<div class="reference"></div>

Then listen for reference elements:

new IntersectionObserver(entries => {
  let item = entries[0]; // Take the first one. There's only one.
  if (item.isIntersecting) console.log("Scroll to the bottom and start requesting data");
}).observe(document.querySelector(".reference")); // Listen for Reference Elements

The results are as follows:

3. Roof suction

There are many ways to achieve element ceiling, such as position: sticky of css, which has poor compatibility; if it is also convenient to implement with cross-observer, it also needs to put a reference element.

Assume that the html structure is as follows:

<!-- Reference element -->
<div class="reference"></div>

<nav>I can suck the top.</nav>

Suppose the scss code is as follows:

nav {
  &.fixed {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
  }
}

Start listening:

let nav = document.querySelector('nav');
let reference = document.querySelector(".reference");

new IntersectionObserver(entries => {

  let item = entries[0];
  let top = item.boundingClientRect.top;

  // When the top value of the reference element is less than 0, that is, at the top of the window, start to suck the top, otherwise remove the top.
  if (top < 0) nav.classList.add("fixed");
  else nav.classList.remove("fixed");

}).observe(reference);

The results are as follows:

But there's a problem. When you roll slowly, you fall into a dead cycle.

To facilitate observation, we add a height and a color to the reference element.

The problem is obvious. When fixed location is added to nav, NAV breaks away from the document stream, natural reference elements fall down, and then cross-over occurs, thus removing fixed location and falling into a dead cycle.

After thinking for a while, the solution is to make the reference element absolutely positioned above nav:

let nav = document.querySelector('nav');
let reference = document.querySelector(".reference");

reference.style.top = nav.offsetTop + "px";

// The following code remains unchanged...

In this way, even if nav is separated from the document stream, it will not affect the location of the reference elements:

4. Animation Show

I believe that many people need this requirement, when an element appears, add an animation to the element, such as gradient, offset, etc.

Assume that the html structure is as follows:

<ul>
  <li></li>
</ul>

Suppose the scss code is as follows:

ul {
 li {
   &.show {
    // Come in on the left by default
    animation: left 1s ease;
    
    // Even numbers come in from the right
    &:nth-child(2n) {
      animation: right 1s ease;
    }
   }
 }
}

@keyframes left {
  from {
    opacity: 0;
    transform: translate(-20px, 20px); // Change right animation to 20px, 20px
  }

  to {
    opacity: 1;
  }
}

Then begin listening:

let list = document.querySelectorAll("ul li");

let observer = new IntersectionObserver(entries => {
  entries.forEach(item => {
    if (item.isIntersecting) {
      item.target.classList.add("show"); // Add the show class name
      observer.unobserve(item.target); // Remove listening
    }
  });
});

list.forEach(item => observer.observe(item));

The results are as follows:

Compatibility

IE is incompatible, but there are Official polyfill

Last

It's worth noting that there must be a crossover between the child and the father. If you want to check the crossover between two non-father-son relationships, it's not good. If you think this article is good, please don't forget to point out some comments and concerns.

Communication

The public number "Front End Cosmological Intelligence Agency" will update the latest and practical front-end skills/technical articles from time to time, and will also occasionally have interesting news on the Internet.

Pay attention to the public number, reply to "1" to get the two-dimensional code of Weixin group chat, learn, communicate and fish together

Posted by Popple3 on Wed, 28 Aug 2019 04:21:27 -0700