这个效果,相较于使用 scroll 事件触发,使用 Intersection Observer API 更加丝滑。下面就是示例代码:

.fade-in-out {
  transition: opacity 0.7s ease-in;
  -webkit-animation-duration: 1s;
  animation-duration: 1s;
  -webkit-animation-fill-mode: both;
  animation-fill-mode: both;
}

.fade-out {
  opacity: 0;
}

.fade-in {
  opacity: 1;
}
const observerOptions = {
  root: null,
  rootMargin: "0px",
  threshold: 0.2,
};

function observerCallback(entries, observer) {
  entries.forEach((entry) => {
    if (entry.isIntersecting) {
      // 淡入视图中观察到的元素
      entry.target.classList.replace("fade-out", "fade-in");
    } else {
     // 淡出观察到的不在视图中的元素
      entry.target.classList.replace("fade-in", "fade-out");
    }
  });
}

const observer = new IntersectionObserver(observerCallback, observerOptions);

const fadeInOutElms = document.querySelectorAll(".fade-in-out");
fadeInOutElms.forEach((el) => observer.observe(el));

具体的参数项见文档,关键参数 threshold 用于指示观察者的回调应该执行目标可见性的多少百分比,就是元素可见部分达到多少时触发回调,可以根据需要调整。