Skip to content

Image 加载优化

图片预加载

图片预加载是指在页面加载时提前加载图片,使其缓存在浏览器中,当用户需要查看图片时立即显示,不需要等待加载。

let image = new Image();
image.src = 'image.jpg';

.image {
  background-image: url('image.jpg');
}

<link rel="preload" href="image.jpg" as="image">

图片懒加载

延迟加载图片,用户滚动到页面上特定位置时才加载图片。

<img data-src="https://xxx.jpg">

getBoundingClientRect

window.addEventListener('scroll', function() {
  this.imgLoadFn()
})
imgLoadFn() {
  let that = this
  let imgGroups = document.getElementsByTagName('img')
  let imgGroupLen = imgGroups && imgGroups.length
  // 最后一张图片还没加载出来,说明需要懒加载
  if (imgGroupLen && imgGroups[imgGroupLen - 1].getAttribute('data-src')) {
    for (let i = 0; i < imgGroups.length; i++) {
      let imgItem = imgGroups[i] || {}
      if (imgItem.getAttribute('data-src')) {
        that.loadImg(imgItem)
      }
    }
  }
},
loadImg(el) {
  // 获取窗口高度
  let docHeight = document.documentElement.clientHeight
  let boundingClientRect = el.getBoundingClientRect()
  let bottom = boundingClientRect.bottom
  let top = boundingClientRect.top
  /* 当元素进入窗口时,才加载真实图片
    bottom: 元素的下边到窗口上边的距离
    top: 元素的上边到窗口上边的距离
  */
  if (top < docHeight && bottom > 0) {
    el.src = el.dataset.src
    el.removeAttribute('data-src')
  }
  // top >= docHeight || bottom <= 0 // 不可见
}

IntersectionObserver

function query(selector) {
  return Array.from(document.querySelectorAll(selector))
}

let observer = new IntersectionObserver(function(entries) {
  entries.forEach(function(entry) {
    let target = entry.target
    console.log(entry.intersectionRatio, entry.isIntersecting)
    // 有时isIntersecting可见,intersectionRatio却为0,修复一下
    if ((entry.intersectionRatio > 0 && entry.intersectionRatio <= 1) ||
    (entry.intersectionRatio === 0 && entry.isIntersecting)) {
      if (target.dataset.src) {
        // dataset.src 就是 获取 "data-src" 属性值
        target.src = target.dataset.src
        target.removeAttribute('data-src')
        // 图片已加载, 解除观察
        observer.unobserve(target)
      } else {
        observer.unobserve(target)
      }
    }
  })
}, { threshold: [0] }) // 默认

query('img').forEach(function(item) {
  // 观察每个图片对象
  observer.observe(item)
})

第三方插件 vue-lazyload

import Vue from 'vue'
import VueLazyload from 'vue-lazyload'

Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'dist/error.png',
  loading: 'dist/loading.gif',
  attempt: 3 // 默认,尝试加载次数
})


<div v-for="(item, index) in imgList" :key="index">
  <img v-lazy="item">
</div>