阅读 43

vue-图片懒加载-指令实现

1.原理

  • 标签传入的url地址临时保存在data-src属性,src指定默认图片
  • 判断方法1:通过IntersectionObserver 判断是否图片在当前浏览器可视区域内
  • 判断方法2:通过监听滚动事件,实时通过 getBoundingClientRect() 获取当前的top 与bottom判断是否在浏览器可视区域内
  • 当在可视区域内,把data-src的url信息赋值给 真正显示的src,并且移除data-src 属性

注意:

  • 这里的right是按右边距离屏幕最左边计算,
  • 这里的bottom 是按低边距离屏幕最上边计算

image.png

2.代码实现

const LazyLoad = {
  // install方法
  install(Vue, options) {
    const defaultSrc = options.default
    Vue.directive('lazy', {
      bind(el, binding) {
        LazyLoad.init(el, binding.value, defaultSrc)
      },
      inserted(el) {
        if (IntersectionObserver) {
          LazyLoad.observe(el)
        } else {
          LazyLoad.listenerScroll(el)
        }
      },
    })
  },
  // 初始化
  init(el, val, def) {
    el.setAttribute('data-src', val)
    el.setAttribute('src', def)
  },
  // 利用IntersectionObserver监听el
  observe(el) {
    var io = new IntersectionObserver((entries) => {
      const realSrc = el.dataset.src
      if (entries[0].isIntersecting) {
        if (realSrc) {
          el.src = realSrc
          el.removeAttribute('data-src')
        }
      }
    })
    io.observe(el)
  },
  // 监听scroll事件
  listenerScroll(el) {
    const handler = LazyLoad.throttle(LazyLoad.load, 300) //定义节流的方法句柄
    LazyLoad.load(el) //第一次自动执行
    window.addEventListener('scroll', () => { //每次滚动都执行
    //使用节流方法防止多次触发
      handler(el)
    })
  },
  // 加载真实图片
  load(el) {
    const windowHeight = document.documentElement.clientHeight
    const elTop = el.getBoundingClientRect().top
    const elBtm = el.getBoundingClientRect().bottom
    const realSrc = el.dataset.src
    if (elTop - windowHeight < 0 && elBtm > 0) {
      if (realSrc) {
        el.src = realSrc
        el.removeAttribute('data-src')
      }
    }
  },
  // 节流
  throttle(fn, delay) {
    let timer
    let prevTime
    return function (...args) {
      const currTime = Date.now()
      const context = this
      if (!prevTime) prevTime = currTime
      clearTimeout(timer)
 
      if (currTime - prevTime > delay) {
        prevTime = currTime
        fn.apply(context, args)
        clearTimeout(timer)
        return
      }
 
      timer = setTimeout(function () {
        prevTime = Date.now()
        timer = null
        fn.apply(context, args)
      }, delay)
    }
  },
}
 
export default LazyLoad

//使用方式
<img v-LazyLoad="xxx.jpg" />

复制代码
文章分类
前端
文章标签