Why do IMAGES need lazy loading

If too many pictures are loaded at one time, js parsing will be blocked, and page startup will be affected. At the same time, too many network resources will be occupied by lazy loading of pictures, and pictures will be loaded only when they appear in the visible area.

Realize the principle of

Method one: the idea of implementation

  1. Set the path of the image to data-src and get all the image nodes
  2. If the image appears in the visible area, replace SRC with data-src
  3. Listen to the page scroll event, plus the anti-shock throll function, the specific code is as follows:
<div class="container">
  <div class="img-area">
    <img class="img" alt="loading" data-src="./img/img1.jpeg" />
  </div>
  <div class="img-area">
    <img class="img" alt="loading" data-src="./img/img2.jpeg" />
  </div>
  <div class="img-area">
    <img class="img" alt="loading" data-src="./img/img3.jpeg" />
  </div>
</div>
Copy the code
  const imgNode = document.querySelectorAll('.img')
  const imgList = Array.from(imgNode)
  const clientHeight = document.documentElement.clientHeight
  // Whether it appears in the viewable area
  function isInVisibale(scrollTop) {
    imgList.forEach((el) = > {
      if (el.offsetTop - scrollTop <= clientHight) {
        loadImg(el)
      }
    })
  }
  // Load the image, replace SRC
  function loadImg(el) {
    if(! el.src) {let src = el.dataset.src
      el.src = src
    }
  }
  / / image stabilization
  function throll(cb, time = 200) {
    let lastime = null
    return function (. arg) {
      let now = Date.now()
      if (now - lastime >= time || lastime === null) {
        cb.apply(this, arg)
        lastime = now
      }
    }
  }
  // Listen for scrolling
  document.addEventListener('scroll', throll(isInVisibale))
Copy the code

The challenge here is to determine if the image is in the visible area,

1. The main calculation method is as follows:

element.offsetTop - document.documentElement.scrollTop <= document.documentElement.clientHeight
Copy the code

2. Alternatively, use getBoundingClientRect() with the address of the MDN: developer.mozilla.org/zh-CN/docs/…

let bound = element.getBoundingClientRect()
bound.top <=docment.documentElement.clientHeight
Copy the code

Then the above function whether or not it appears in the visual area can be modified to

  function isInVisibale() {
    imgList.forEach((el) = > {
      let bound = el.getBoundingClientRect()
      if (bound.top <= clientHeight) {
        loadImg(el)
      }
    })
  }

Copy the code

Method 2: IntersectionObserver() API can be used to automatically observe whether elements are in the viewport. Method 1 will continuously monitor the scrolling of the page, which will have a certain impact on the page performance. It’s better to use insterSetionObserver() to listen for elements to appear in the viewable area, but it’s not compatible and Chrome 51+ only supports it.

const imgNode = document.querySelectorAll('.img')
const imgList = Array.from(imgNode)
// Start a listener
const Observe = new IntersectionObserver(function (observes) {
  observes.forEach((observe) = > {
    let el = observe.target
    // Judge by intersectionRatio
    if (observe.intersectionRatio > 0 && observe.intersectionRatio <= 1) {
      loadImg(el)
    }
    // Cancel the view when the image loads and fails
    el.onload = el.onerror = () = > Observe.unobserve(el)
  })
})
// Observe all the images
imgList.forEach((el) = > {
  Observe.observe(el)
})
// Replace the image
function loadImg(el) {
  if(! el.src) {let src = el.dataset.src
    el.src = src
  }
}
Copy the code

Vue uses v-lazyload instruction to achieve lazy loading

In vUE framework, we will often use V-HTML, V-text, V-IF, V-show, V-for and other instructions to carry out agile development, so we can also customize our own instructions to facilitate our daily development, the specific source code is as follows

Analysis of ideas:

  1. Install a custom VUE command, and check whether a Function such as IntersectionObserver is supported in the inserted hook function of the vUE command. If not, use the monitor scroll event
  2. Register with local component directive:{}, or global component vue.directive()
  3. The page uses direct V-lazy =’xxx.jpg’
const lazyLoad = {
  // When the bound element is inserted into the parent node
  inserted (el, binding) {
    let src = binding.value
    console.log(11, src)
    // Verify whether IntersectionObserver() is supported
    if (IntersectionObserver) {
      observe(el, src)
    } else {
      observeScroll(el, src)
    }
  }
}

/ / to monitor API
function observe (el, src) {
  const Observer = new IntersectionObserver(observes= > {
    console.log(observes[0].isIntersecting)
    if (observes[0].isIntersecting && ! el.src) { el.src = src el.removeAttribute('data-src')
      Observer.unobserve(el)
    }

  })
  Observer.observe(el)
}
// Listen to the scroll API
function observeScroll (el, src) {
  document.addEventListener('scroll', throll(isInVisibale(el, src)))
}
const clientHeight = document.documentElement.clientHeight
// Higher order function
function isInVisibale (el, src) {
  return function () {
    let bound = el.getBoundingClientRect()
    if (bound.top <= clientHeight) {
      if(! el.src) { el.src = src } } } }// Buffering: use higher-order functions and closures
function throll (cb, time = 200) {
  let lastime = null
  return function (. arg) {
    let now = Date.now()
    if (now - lastime >= time || lastime === null) {
      cb.apply(this, arg)
      lastime = now
    }
  }
}
export default lazyLoad
Copy the code

conclusion

  1. Lazy loading of images is necessary to improve web performance and user experience
  2. You can monitor scroll events and interSectionObserve() to determine whether an image appears in the visible area
  3. The Vue framework can write a directive v-loayload to implement lazy loading of images