• 原生js


    目前图片懒加载的方式主要有两种:

      1、利用 getBoundingClientRect API得到当前元素与视窗的距离来判断

      2、利用h5的新API IntersectionObserver 来实现

    getBoundingClientRect

      Element.getBoundingClientRect() 方法返回值是一个 DOMRect 对象,包含了该元素一组矩形的集合:是与该元素相关的css边框集合(top, left, right, bottom)。 

    我们可以采用如下方法来判断是否在可视区域:

    isViewport (el) {
      const viewWidth = window.innerWidth || document.documentElement.clientWidth;
      const viewHeight = window.innerHeight || document.documentElement.clientHeight;
      let { top, left, right, bottom } = el.getBoundingClientRect()
      return (
        top >= 0 &&
        left >= 0 &&
        right <= viewWidth &&
        bottom <= viewHeight
      )
    }

    getBoundingClientRect 方式来实现需要监听 scroll 方法来配合,对于浏览器的性能会有一定的问题。

    IntersectionObserver

      而 IntersectionObserver 方法是在2016年初提出来的,该API提供了一种异步观察目标元素相对与 root 元素是否进入了可视区域。作为一个新兴API,会有一定的兼容问题,点击查看兼容性
      当 IntersectionObserver 对象被创建,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值,但是可以在同一个观察者对象中配置监听多个目标元素。
     

     属性

      root: 所监听对象的具体祖先元素。如果未传入值或值为null,则默认使用顶级文档的视窗。

      rootMargin: 计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。

      thresholds: 可以是一个单独的number,也可以是一个number数组。当 root 元素与 target 元素相交达到该值的时候会执行回调。当值设定为0时,那么 target 元素有一个像素出现在 root 元素,回调就会执行;如果值设为1,那么就是当 target 元素完全出现在 root 元素当中才会执行。默认为0。如果当值设定为 [0, 0.25, 0.5, 0.75, 1] 时,那么每满足一个值就会回调一次。该值设定的时候不是复数,当取值的时候为复数:

    var observer = new IntersectionObserver(_observer, {
        root : null,
        threshold: [] // 单数
    });
    
    observer.thresholds // 复数

     方法

      IntersectionObserver.disconnect: 停止所有监听工作

      IntersectionObserver.observe: 开始监听一个目标元素

      IntersectionObserver.takeRecords: 返回所有观察目标对象的数组

      IntersectionObserver.unobserve: 停止监听特定目标元素。

     
    下面添上图片懒加载 js 代码:
    function LazyLoad (config) {
      this.default = {
        root: null,
        threshold: 0
      }
      this.settings = Object.assign(this.default, config)
      this.images = []
      this.observer = null
      this.init()
    }
    
    LazyLoad.prototype = {
      init () {
        if (!window.IntersectionObserver) {
          this.loadImages()
          return
        }
    
        this.images = document.querySelectorAll(this.settings.selector || '[data-src]')
    
        let _this = this
        let observeConfig = {
          root: this.settings.root,
          rootMargin: this.settings.rootMargin,
          threshold: [this.settings.threshold]
        }
    
        this.observer = new IntersectionObserver(changes => {
          Array.prototype.forEach.call(changes, entry => {
    
            if (entry.isIntersecting) {
    
              let target = entry.target
              _this.observer.unobserve(target)
              let src = target.dataset.src
    
              if (target.tagName.toLowerCase() === 'img') {
                target.src = src
              } else {
                target.style.backgroundImage = `url(${src})`
              }
    
              target.removeAttribute('data-src')
            }
          })
        }, observeConfig)
    
        Array.prototype.forEach.call(this.images, image => {
          _this.observer.observe(image)
          image.src = _this.settings.placeholder
        })
    
      },
    
      loadImages () {
        let _this = this
        _this.replaceSrc()
    
        let hasDone = false
        function _scroll() {
          if (hasDone) return
          hasDone = true
          setTimeout(() => {
            _this.replaceSrc()
            hasDone = false
          }, 100)
        }
        window.onscroll = _scroll
      },
    
      replaceSrc () {
        let _this = this
        let imgs = document.querySelectorAll(this.settings.selector || '[data-src]')
        Array.prototype.forEach.call(imgs, image => {
          if (!image.src) image.src = _this.settings.placeholder
          let src = image.dataset.src
          if (_this.isInnerView(image)) {
            if (image.tagName.toLowerCase() === 'img') {
              image.src = src
            } else {
              image.style.backgroundImage = `url(${src})`
            }
            image.removeAttribute('data-src')
          }
        })
      },
    
      isInnerView (el) {
        const viewWidth = window.innerWidth || document.documentElement.clientWidth;
        const viewHeight = window.innerHeight || document.documentElement.clientHeight;
        let { top, left, right, bottom } = el.getBoundingClientRect()
        return (
          top >= 0 &&
          left >= 0 &&
          right <= viewWidth &&
          bottom <= viewHeight
        )
      },
    
      destroy () {
        this.observer.disconnect();
      }
    }
     
     
     
  • 相关阅读:
    python3使用django1.11不支持MYSQL-python的解决办法
    abp学习目录
    日常网站整理
    C#使用TransactionScope实现事务代码
    CSS禁止选择
    数据库三种事务
    设计模式总章
    几种排序方法的总结
    将图片压缩成大小格式小的图片
    常用的wsdl地址
  • 原文地址:https://www.cnblogs.com/kdcg/p/11195761.html
Copyright © 2020-2023  润新知