图片 - 懒加载

图片的懒加载其实就是延迟加载图片,仅当图片出现在可视区域内(或离可视区域有一定距离时)才开始加载图片。

对于有大量图片的网页来说,懒加载可以避免在打开网页时同时加载过多资源,起到性能优化的作用。

原理

初始加载时不设置imgsrc属性(或者src属性设置成占位图片地址),将真实的图片地址放置在 data-src属性里,后续当图片进入到页面的可视区域后,将data-src属性值取出赋值给src属性,此时再去请求图片

相关插件

如何判断图片处于页面可视区域?

方法一:getBoundingClientRect (推荐)

Element.getBoundingClientRect()方法返回一个DOMRect对象,该对象包含的属性包括Element元素的大小(widthheight)及其相对于视口左上角的位置(topleftrightbottom

function isInViewport(el) {
  const rect = el.getBoundingClientRect()
  const viewportSize = getViewportSize()
  const vpHeight = viewportSize.width
  const vpWidth = viewportSize.height

  return 0 < rect.bottom && rect.top < vpHeight ||
         0 < rect.right && rect.left < vpWidth
}
1
2
3
4
5
6
7
8
9

方法二:offsetTop/offsetLeft、scrollTop/srollLeft

function isInViewport(el) {
  const scrollOffset = getScrollOffset()
  const scrollTop = scrollOffset.scrollTop
  const scrollLeft = scrollOffset.scrollLeft

  const viewportSize = getViewportSize()
  const vpHeight = viewportSize.height
  const vpWidth = viewportSize.width

  const height = el.offsetHeight
  const width = el.offsetWidth

  const elPos = getElementPosition(el)
  const offsetLeft = elPos.offsetLeft
  const offsetTop = elPos.offsetTop

  return -height < offsetTop - scrollTop && offsetTop - scrollTop < vpHeight ||
         -width < offsetLeft - scrollLeft && offsetLeft - scrollLeft < vpWidth
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

方法三:原生 IntersectionObserver 函数

Referrence:

工具函数

// 获取视口尺寸
function getViewportSize(win = window) {
  if (win.innerWidth !== undefined) {
    return {
      width: window.innerWidth,
      height: window.innerHeight
    }
  }
  const doc = win.document
  if (doc.compatMode === 'CSS1Compat') {
    // 标准模式下的 IE(或任何浏览器)
    return {
      width: doc.documentElement.clientWidth,
      height: doc.documentElement.clientHeight
    }
  }

  // 怪异模式下的浏览器
  return {
    width: doc.body.clientWidth,
    height: doc.body.clientHeight
  }
}

// 获取元素距离文档的距离
function getElementPosition(el) {
  let offsetLeft = 0, offsetTop = 0
  while(el !== undefined) {
    offsetLeft += el.offsetLeft
    offsetTop += el.offsetTop
    el = el.offsetParent
  }
  return {
    offsetLeft
    offsetTop
  }
}

// 获取文档的滚动距离
function getScrollOffset(win = window) {
  if (win.pageXOffset !== undefined) {
    // 除了 IE8 及更早版本,其他浏览器都能用
    return {
      scrollTop: win.pageYOffset,
      scrollLeft: win.pageXOffset
    }
  }
  const doc = win.document
  if (doc.compatMode === 'CSS1Compat') {
    // 标准模式下的 IE(或任何浏览器)
    return {
      scrollTop: doc.documentElement.scrollTop,
      scrollLeft: doc.documentElement.scrollLeft
    }
  }

  // 怪异模式下的浏览器
  return {
    scrollTop: doc.body.scrollTop,
    scrollLeft: doc.body.scrollLeft
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62