无奖问答系列:你所理解的IntersectionObserver

翻译

IntersectionObserver:交叉口监控

异步操作,不随着目标元素的滚动同步触发。

即只有线程空闲下来,才会执行观察器。这意味着,这个观察器的优先级非常低,只在其他任务执行完,浏览器有了空闲才会执行。

作用

监听目标元素与其祖先或视窗交叉状态的手段,其实就是观察一个元素是否在视窗可见。

语法

创建原生构造函数 IntersectionObserver的一个实例,接受两个参数两个参数:callback是当元素可见性变化时的回调函数,option是配置对象(该参数可选)。

let io= new IntersectionObserver(callback, options)

实例的方法

构造函数的返回值是一个观察器实例。
特别注意:实例io.observe方法可以指定观察哪个元素。

// 开始观察,
io.observe(document.getElementById('example'));

// 停止观察
io.unobserve(element);

// 关闭观察器
io.disconnect();

若想要观察多个元素,可以调用多次io.observe(document.getElementById('***'));

io.observe(document.getElementById('example1'));
io.observe(document.getElementById('example2'));
io.observe(document.getElementById('example3'));

参数

callback:当目标元素有可见性变化的时候,执行

callback默认会触发两次。一次是目标元素刚刚进入视口(开始可见),另一次是完全离开视口(开始不可见)。

var io = new IntersectionObserver(
  entries => {
  	//entries:数组
    console.log('example',entries);
  }
);

entries是个数组,如果有受观察的多个元素的可见性发生了变化,entries 内的数组成员就能有多个。
entries分析

console.log('example',entries);
在这里插入图片描述

  • boundingClientRect:目标元素与可视视图的距离,内容与原生的document.boundingClientRect()返回值一致。其中一共有六个属性:left、right、top、bottom、x、y、width、height。
  • intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0。
  • intersectionRect:目标元素与视口(或根元素)的距离,也有有六个属性:left、right、top、bottom、x、y、width、height。
  • isIntersecting:目标元素与视图是否相交。
  • isVisible:目标元素是否可见。
  • rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
  • target:目标元素。
  • time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒。
option:配置,可以控制什么时候触发callback回调
var io = new IntersectionObserver(
    //callback
   	entries => {},
   //option
  	{	
  		root: document.querySelector('.container'),
  		rootMargin: "500px 0px" 
  		threshold: [0, 0.25, 0.5, 0.75, 1],
  	}
);
  • threshold: [0, 0.25, 0.5, 0.75, 1]表示,目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。
  • root:更改目标元素有可见性变化的参照物。默认是目标元素与根节点之间的比较,现在为class=‘container’与目标元素的对比。当.example出现在.container视图之中,才会触发callback回调。
  • rootMargin: “500px 0px” ,不懂这是干嘛的,还没用到。
    在这里插入图片描述

vue中基本使用方法

<template>
  <div class="box">
    <div class="container" id="container">
      <div class="example" id="example1"></div>
    </div>
  </div>
</template>
<script>
 export default {
   mounted () {
     this.observer()
   },
   methods: {
     observer(){
      let io = new IntersectionObserver(
        entries => {
          console.log('example',entries);
        },
        {
          root:document.getElementById('container'),
          threshold: [0, 0.25, 0.5, 0.75, 1]
        }
      )
      io.observe(document.getElementById('example1'));
     }
   }
 }
</script>
<style lang="less" scoped>
.box{
  height: 100vh;
  overflow: auto;
  background-color: darkgray;
  .container{
    width: 500px;
    height: 500px;
    overflow: auto;
    margin: 0 auto;
    background-color: antiquewhite;
    margin-top: 100px;
    .example{
      width: 200px;height: 200px;
      margin-top: 500px;
      background-color: brown;
      margin-bottom: 100px;
      margin-left: 100px;
    }
  }

}
</style>

懒加载图片正文

思路
  1. 图片懒加载的图片一般都是一个list,那么一个list就需要用v-for循环去渲染展示。在html的<img>便签中,用自定义的一个data-src代替src,为了后期加载的时候能够通过dom元素获取到在src上对应的图片url。

    <div class="img-item" v-for="(item,index) in imageList" :key="index" >
        <img class="my-img" :data-src='item.PicUrlComplete' >
      </div>
    
  2. 获取dom元素需要在图片标签渲染结束之后,这里就涉及到vue的生命周期问题。实际操作中可能会因为在没有渲染完成之前就获取不到dom元素这样的问题。这里我是在获取接口,返回数据成功之后在this.$nextTick获取目标元素my-img

    	this.$nextTick(function(){
    	   this.imageDoms = Array.from(document.querySelectorAll(".my-img"));
    	})
    

    原本这里是想使用静态数据,但是为了更加贴合实际,还是选择使用获取接口的方式,这样会发现很多问题。

  3. 创建IntersectionObserver的实例之后,由于目标元素有多个,所以就要一个个去设置监听。

    let io = new IntersectionObserver(
      entries => {
         entries.forEach(item=>{
            if(item.isIntersecting){
              item.target.src = item.target.dataset.src;
            }
          })
        },
      )
     //循环设置监听
    this.imageDoms.forEach(function(item) {
      io.observe(item);
    });
    
  4. 展示:在IntersectionObserver实例的 回调中设置,目标元素有多个,那么回调值也循环去处理。一旦目标元素出现(item.isIntersecting>=0),那么就将目标元素的item.target.dataset.src赋值给item.target.src,这样对于的图片上就有src值,就能展示图片了。

  5. 最后记得要在beforeDestroy生命周期里面将创建的IntersectionObserver实例销毁,不然会造成一定的内存泄漏。

完整代码
<template>
  <div class="box">
    <div class="img-list">
      <div class="img-item" v-for="(item,index) in imageList" :key="index" >
        <img class="my-img" :data-src='item.PicUrlComplete' >
      </div>
    </div>
  </div>
</template>
<script>
import {
	infoposterlist,
} from "@/api/wyUsedInterface.js"
 export default {
    data() {
      return {
        imageList: [],
        io:null
      }
    },
    mounted () {
      this.getsterPic()
    },
  	beforeDestroy() {
      this.io.disconnect()
    },
   	methods: {
      observer(){
        let imageDoms = Array.from(document.querySelectorAll(".my-img"));
        this.io = new IntersectionObserver(
          entries => {
            entries.forEach(item=>{
              if(item.isIntersecting){
                item.target.src = item.target.dataset.src;
              }
            })
          },
        )
        imageDoms.forEach((item)=> {
          this.io.observe(item);
        });
      },
      async getsterPic(){
        try{
          let data = {
            ***
          }
          let res = await infoposterlist(data)
          if(res.IsSuccess){
            this.imageList = res.Result.Results
            this.$nextTick(function(){
              this.observer()
            })
          }
        }catch(e){
        }finally{
        }
      },
   	}
 }
</script>
<style lang="less" scoped>
.box{
  height: 100vh;
  overflow: auto;
  background-color: darkgray;
  .img-list{
    margin-top: 1000px;
    position: relative;
    width:100%;
    .img-item{
      float: left;
      width: 200px;
      padding: 5px;
      img{
        border: 1px solid #ddd;
        width: 100%;
        object-fit: contain;
      }
    }
  }
}
</style>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值