啊??还在用监听滚动条滚动位置实现图片懒加载?欢乐时光来了,使用 Intersection Observer API 优雅实现滚动条相关操作!

大家下午好。听说在实现一些需要监听滚动条滚动到某个元素需要执行某段神秘代码的需求时,大伙总是不太乐意,现给大家介绍一个不用监听滚动事件就能完成需求的api,希望能给一点点启发。

废话少说,先上效果

  • 懒加载
  • 瀑布流
  • 视频暂停

上代码

HTML

html 复制代码
/* html */
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Intersection Observer API</title>
  <style>
    * {
      padding: 0;
      margin: 0;
    }
    .wrapper {
      display: flex;
      flex-wrap: wrap;
    }
    img {
      width: 400px;
      margin: auto;
    }
  </style>
</head>
<body>
  <div class="wrapper">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1956604245,3662848045&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=4198287529,2774471735&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1223089837,2011531023&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=2529476510,3041785782&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=727460147,2222092211&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3779234486,1094031034&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=2763645735,2016465681&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=38705621,4040292245&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3691080281,11347921&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=309902808,4013662088&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3915743384,2060495762&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=814015239,3764270914&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=735474575,14049849&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=55748064,2074988836&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1415984692,3889465312&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1635608122,693552335&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=4229354459,3466205664&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=334080491,3307726294&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=334080491,3307726294&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=801209673,1770377204&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1010739515,2488150950&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=755629088,1584786319&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=2359570649,2574326109&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3326728979,3352004316&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1972611367,1123866192&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1418407542,1794380926&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1879685954,2134278564&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=2466425392,342874463&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3355440349,3059059541&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=1335405753,180526972&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3522949495,3570538969&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=434014116,2108959724&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3439093793,987421329&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=238793329,1979556309&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=3355871248,953827123&fm=193&f=GIF">
    <img src="./imgs/0.png" data-src="https://t7.baidu.com/it/u=2757385166,2243114851&fm=193&f=GIF">
  </div>
  <script src="./index.js"></script>
</body>
</html>

JS

js 复制代码
// index.js
const ob = new IntersectionObserver(entries => {
  entries.forEach(entrie => {
    if(entrie.isIntersecting) {
        const img = entrie.target;
        img.src = img.dataset.src;
        ob.unobserve(img)
    }
  })
}, {
  threshold: 0
})

const imgs = document.querySelectorAll('img[data-src]');
imgs.forEach(img => {
  ob.observe(img)
})

完事,下次再见

啊?客官还要解释?那好吧

接下来就是隆重推出今天的主角 IntersectionObserver API,这是一套用来监听 html 元素是否与指定元素有 交叉关系 的API。 就拿以下代码解释

js 复制代码
const ob = new IntersectionObserver(
  (entries) => {
    console.log(entries);
  },
  {
    root: null,
    rootMargin: 0,
    threshold: 0,
  }
);
ob.observe(dom);
  • IntersectionObserver 第一个参数是回调函数,回调参数是一组被观察元素的具体交叉情况

  • 第二个参数是配置项

    • root: 表示被观察元素与哪个元素是否产生交叉,只能填被观察元素的父元素(祖先元素),默认 null 表示视口元素
    • rootMargin: 表示被观察元素与 root 之间的距离,如值为 10 ,则被观察元素与 root 相距小于等于 10 就会视为已交叉;默认为0;如下图
    • threshold: 表示交叉的阈值,值为 0-1 之间,默认为0,表示交叉了多少才视为交叉,如下图
  • ob.observe(dom) 表示要观察哪个元素;
  • 下图为回调函数中的参数;

主要关注 isInterestingtarget 这两个属性

  • isInteresting 表示是否交叉
  • target 表示目前交叉的元素

回归主题

那么我们回到上面的懒加载的实现,只要监听每张图片是否与视口交叉即可。请看

js 复制代码
const ob = new IntersectionObserver(entries => {
  entries.forEach(entrie => {
    if(entrie.isIntersecting) {
        const img = entrie.target; // 获取当前交叉的图片
        img.src = img.dataset.src; // 将 data-src 的值,赋值给 src
        ob.unobserve(img) // 已加载的图片就没有必要再监听了, 移除监听
    }
  })
}, {
  threshold: 0 // 只要一出现在视口就判定已交叉
})

const imgs = document.querySelectorAll('img[data-src]'); // 获取所有带着data-src属性的图片元素
imgs.forEach(img => {
  ob.observe(img) // 遍历监听每一张图片
})

实现瀑布流,只需监听加载中的元素是否交叉即可

HTML

html 复制代码
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Intersection Observer API</title>
    <style>
      * {
        padding: 0;
        margin: 0;
      }
      .wrapper {
        display: flex;
        flex-wrap: wrap;
      }
      img {
        width: 350px;
        margin: auto;
      }
      .mycircle {
        stroke-dasharray: 125.6px;
        animation: move linear 1s infinite;
        transform-origin: center;
        stroke-dashoffset: 30px;
        fill: none;
        stroke: #666;
        stroke-width: 5px;
      }
      @keyframes move {
        0% {
          transform: rotate(0deg);
        }
        100% {
          transform: rotate(360deg);
        }
      }
    </style>
  </head>
  <body>
    <div class="wrapper">
      <img src="https://t7.baidu.com/it/u=1956604245,3662848045&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=4198287529,2774471735&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=1223089837,2011531023&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=2529476510,3041785782&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=727460147,2222092211&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=3779234486,1094031034&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=2763645735,2016465681&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=38705621,4040292245&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=3691080281,11347921&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=309902808,4013662088&fm=193&f=GIF">
      <img src="https://t7.baidu.com/it/u=3915743384,2060495762&fm=193&f=GIF">
    </div>
    <div class="spin" style="text-align: center">
      <svg width="150" height="150" viewBox="0 0 50 50">
        <circle class="mycircle" cx="25" cy="25" r="20">
          <animateTransform
            attributeName="transform"
            type="rotate"
            from="0"
            to="360"
            dur="1s"
            repeatCount="indefinite"
          />
        </circle>
      </svg>
    </div>
    <script src="./index2.js"></script>
  </body>
</html>

JS

js 复制代码
const img = [
    "https://t7.baidu.com/it/u=814015239,3764270914&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=735474575,14049849&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=55748064,2074988836&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=1415984692,3889465312&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=1635608122,693552335&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=4229354459,3466205664&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=334080491,3307726294&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=334080491,3307726294&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=801209673,1770377204&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=1010739515,2488150950&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=755629088,1584786319&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=2359570649,2574326109&fm=193&f=GIF",
    "https://t7.baidu.com/it/u=3326728979,3352004316&fm=193&f=GIF",
  ]
function loadImage(imgs) {
  imgs.forEach(item => {
    const img = document.createElement('img')
    img.src = item
    document.querySelector('.wrapper').appendChild(img)
  })
}
const ob = new IntersectionObserver(entries => {
  if(entries[0].isIntersecting) {
    setTimeout(() => {
      loadImage(img)
    }, 1000);
  }
}, {
  threshold: 0
})
const spin = document.querySelector('.spin');
ob.observe(spin) // ### 监听加载中的元素是否交叉

实现视频暂停

HTML

html 复制代码
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .wrapper {
      width: 100vw;
      height: 100vh;
      text-align: center;
    }
    .video {
      margin-top: 100px;
      margin-bottom: 1000px;
    }
  </style>
</head>
<body>
  <div class="wrapper">
    <video class="video" controls autoplay="true" src="哪吒之魔童降世.Nezha.Birth.of.the.Demon.Child.2019.HD1080P.国语中字.mp4" width="80%"></video>
  </div>
  <script src="./index3.js"></script>
</body>
</html>

JS

js 复制代码
const ob = new IntersectionObserver(entries => {
    const video = entries[0].target
    if(entries[0].isIntersecting) {
    video.play()
  } else {
    video.pause()
  }
}, {
  threshold: 1 // 只要视频有一点不见了就暂停
})

const video = document.querySelector('.video');
ob.observe(video)

真的没了,下次再见!

相关推荐
熊的猫9 分钟前
webpack 核心模块 — loader & plugins
前端·javascript·chrome·webpack·前端框架·node.js·ecmascript
速盾cdn16 分钟前
速盾:vue的cdn是干嘛的?
服务器·前端·网络
四喜花露水1 小时前
Vue 自定义icon组件封装SVG图标
前端·javascript·vue.js
前端Hardy1 小时前
HTML&CSS: 实现可爱的冰墩墩
前端·javascript·css·html·css3
web Rookie1 小时前
JS类型检测大全:从零基础到高级应用
开发语言·前端·javascript
Au_ust2 小时前
css:基础
前端·css
帅帅哥的兜兜2 小时前
css基础:底部固定,导航栏浮动在顶部
前端·css·css3
工业甲酰苯胺2 小时前
C# 单例模式的多种实现
javascript·单例模式·c#
yi碗汤园2 小时前
【一文了解】C#基础-集合
开发语言·前端·unity·c#
就是个名称2 小时前
购物车-多元素组合动画css
前端·css