Skip to content

Latest commit

 

History

History
151 lines (105 loc) · 2.93 KB

4.0.9IntersectionObserver 触底-吸顶-动画.md

File metadata and controls

151 lines (105 loc) · 2.93 KB

2. 触底

我们在列表底部放一个参照元素,然后让交叉观察者去监听;

假设html结构如下:

<!-- 数据列表 -->

<ul>
  <li>index</li> // 多个li
</ul>

<!-- 参照元素 -->
<div class="reference"></div>

然后监听参照元素:

new IntersectionObserver(entries => {
  let item = entries[0]; // 拿第一个就行,反正只有一个
  if (item.isIntersecting) console.log("滚动到了底部,开始请求数据");
}).observe(document.querySelector(".reference")); // 监听参照元素

3. 吸顶

实现元素吸顶的方式有很多种,如css的position: sticky,兼容性较差;如果用交叉观察者实现也很方便,同样也要放一个参照元素;

假设html结构如下:

<!-- 参照元素 -->
<div class="reference"></div>

<nav>我可以吸顶</nav>

假设scss代码如下:

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

开始监听:

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

new IntersectionObserver(entries => {

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

  // 当参照元素的的top值小于0,也就是在视窗的顶部的时候,开始吸顶,否则移除吸顶
  if (top < 0) nav.classList.add("fixed");
  else nav.classList.remove("fixed");

}).observe(reference);

但是有个问题,当你滚动的慢的时候,会掉进一个死循环: 当给nav增加fixed定位时,nav脱离了文档流,自然参考元素会往下掉,然后往下掉又发生了交叉,从而去除fixed定位,陷入一个死循环;

思考了一会,解决办法是,让参考元素绝对定位至nav的上方:

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

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

// 以下代码不变 ... 这样,即使nav脱离的文档流,也不会影响参考元素的位置

动画展示

假设html结构如下:

<ul>
  <li></li> // 多个li
</ul>

假设scss代码如下:

ul {
 li {
   &.show {
    // 默认从左边进来
    animation: left 1s ease;
    
    // 偶数从右边进来
    &:nth-child(2n) {
      animation: right 1s ease;
    }
   }
 }
}

@keyframes left {
  from {
    opacity: 0;
    transform: translate(-20px, 20px); // right动画改成20px, 20px即可
  }

  to {
    opacity: 1;
  }
}

然后开始监听:

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

let observer = new IntersectionObserver(entries => {
  entries.forEach(item => {
    if (item.isIntersecting) {
      item.target.classList.add("show"); // 增加show类名
      observer.unobserve(item.target); // 移除监听
    }
  });
});

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

参考