IntersectionObserver

509 阅读3分钟

前言

2020年仅剩下最后几天啦,提前预祝各位程序猿和程序媛们元旦快乐,之前有更新过一些基础的内容,根据评论区的反馈,开始更新一些前端进阶的知识,带大家了解一些并非常用但是非常实用的知识,同事看了直呼内行

基础实现滚动加载与懒加载的思路

  • 监听浏览器滚动条滚动事件
  • 比较滚动scrollTop与元素的clientTop
  • 如果元素已经进入视口进行相应的加载与渲染

相信说到滚动加载与懒加载,大家能想到的都是以上的这种思路,基于浏览器滚动事件实现,这种方式实现封装较为困难,需要考虑的因素较多,比如执行时机,元素渲染图片加载都存在异步的考虑情况,性能方面由于滚动会不断执行代码逻辑,需要考虑函数节流等各类封装

IntersectionObserver

  • 通过IntersectionObserver监听元素是否进入视口
  • 如果元素已经进入视口进行相应的加载与渲染
  • 基于IntersectionObserver实现滚动加载与懒加载实现会非常简单,并且在性能上会得到很大的提升,可以判断元素是否进入视口,也可以判断元素是否进入自己设置的某个根节点

    IntersectionObserver - API

    基础用法

    var io = new IntersectionObserver(callback, option);
    
    // 开始观察
    io.observe(document.getElementById('example'));
    
    // 停止观察
    io.unobserve(element);
    
    // 关闭观察器
    io.disconnect();
    

    callback是监听之后的回掉

    callback函数的参数(res)是一个数组,每个成员都是一个IntersectionObserverEntry对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,res数组就会有两个成员。

    option 自定义参数

    • time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
    • target:被观察的目标元素,是一个 DOM 节点对象
    • rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
    • boundingClientRect:目标元素的矩形区域的信息
    • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
    • intersectionRatio:目标元素的可见比例,即intersectionRect占
    • boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0

    基于 IntersectionObserver 的全局封装及使用

    class Intersection {
        constructor(data) { // 构造器
            for (let i in data) {
                this[i] = data[i]
            }
    
            this.selector = document.querySelectorAll(this.dom)[0]
        }
        // 定义类方法
        observer() {
            this.io = new IntersectionObserver(
                (changes) => {
                    if(this.callback) this.callback()
                    changes[0].isIntersecting ? this.next({ changes, cb: this.scrollInView }) : this.next({ changes, cb: this.scrollOutView })
                },
                {
                    ...this.option
                }
            );
    
            //开启dom监听
            if (this.selector) {
                this.io.observe(this.selector);
            }
    
        }
        next({ changes, cb }) {
            if (cb) cb(changes);
        }
        unobserve() {
            if (this.selector) {
                this.io.unobserve(this.selector)
            }
        }
        disconnect() {
            if (this.selector) {
                this.io.disconnect();
            }
        }
    }
    
    
    const intersection = (data) => {
        const io = new Intersection(data)
        io.observer()
        return io
    }
    
    
    const install = function (Vue, opts = {}) {
        Vue.prototype.$intersection = intersection;
    };
    
    export default install
    

    使用:

    //开启
        this.io = this.$intersection({
          dom: '#test',
          option: {
            root: document.querySelector('.container'), //root 如果不传默认为是body
          }, //option 可传 intersectionobserver_api 可传的全部入参数
          callback: (e) => {
            console.log('回掉', e);
          },
          scrollInView: function (e) {
            console.log('元素进入', e, this);
          },
          scrollOutView: (e) => {
            console.log('元素离开', e, this);
          },
        });
    

    以上就是IntersectionObserver的使用,是不是很简单,快去为项目的滚动进行你的优化吧

    课后扩展

    知道MutationObserver的用途吗,尤大大又是怎样基于MutationObserver实现nextTick的呢,最新版vue3.0 又将MutationObserver替换成了什么