圖片懶載入(IntersectionObserver)

hackLi發表於2019-03-26

scroll實現

上次我們聊到的是throttle和debounce去實現 實現圖片懶載入(throttle, debounce)

不過,就算throttle和debounce是實現圖片懶載入,但是scroll事件密集發生,計算量很大,容易造成效能問題。

IntersectionObserver

這api主要負責監聽元素和"視口"(viewport)的關係,我就不多講述了

  • API

Intersection Observer - Web API 介面參考 | MDN

IntersectionObserver API 使用教程 - 阮一峰

程式碼實現

下方附帶github原始碼

class LazyLoad{
    constructor(images, options = {}) {
        this.setting = Object.assign({}, {src: 'data-src', srcset: 'data-srcset'}, options)
        this.images = images
        this.observer = null
        this.init()
    }
    init() {
        let observerConfig = {
            root: null,
            rootMargin: '0px',
            threshold: [0]
        }
        this.observer = this.intersectionObserver(observerConfig)
        this.images.forEach(image => this.observer.observe(image))
    }
}
複製程式碼
  • observerConfig中的屬性
  1. root: 檢視節點,null時預設為body(應該是)
  2. rootMargin 根元素的margin
  3. threshold屬性決定了什麼時候觸發回撥函式。它是一個陣列,每個成員都是一個門檻值,預設為[0],即交叉比例(intersectionRatio)達到0時觸發回撥函式
生成IntersectionObserver例項
intersectionObserver(config) {
    return new IntersectionObserver(entries => {
    	entries.forEach(entry => {
    	  const target = entry.target
    	  // 到元素出現在檢視中
    	  if(entry.intersectionRatio > 0) {
            this.observer.unobserve(target)
            // 設定img真實src路徑
            this.setImgsrc(target)
    	  }
    	})
    }, config)
}
複製程式碼
設定img真實src路徑
setImgsrc(target){
	const src = target.getAttribute(this.setting.src)
	const srcset = target.getAttribute(this.setting.srcset)
	// 判斷是否為img節點
	if('img' === target.tagName.toLowerCase()) {
        if(src) {
            target.src = src
        }
        if(srcset) {
            target.srcset = srcset
        }
	} else {
            target.style.backgroundImage = `url(${src})`
	}
}
複製程式碼
新增全域性設定

這一個步驟可能多餘了,但是在實現元件的時候經常會有全域性設定,方面更改

const glabolConfig = {
    src: 'data-src',
    srcset: 'data-srcset'
}
class LazyLoad{
    constructor(images, options = {}, glabolConfig) {
        this.setting = Object.assign({}, glabolConfig, options)
    }
}
複製程式碼
保護區域性變數
;(function(window, glabolConfig) {
    class LazyLoad{
        ...
    }
})(window, glabolConfig);	
複製程式碼
無new生成例項
window.lazyLoad = (images, options = {}) =>{
    return new LazyLoad(images, options, glabolConfig)
}
複製程式碼
使用
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <style>
        	img, body, ul, li, html {
        		margin: 0;
        		padding: 0;
        	}
        	img{
        		height: 700px;
        		width: 100vw;
        	}
        </style>
    </head>
    <body>
        <ul>
            <li><img src="img/10.gif" data-src="img/1.jpg"></li>
            <li><img src="img/10.gif" data-src="img/2.jpg"></li>
            <li><img src="img/10.gif" data-src="img/3.jpg"></li>
            <li><img src="img/10.gif" data-src="img/4.jpg"></li>
            <li><img src="img/10.gif" data-src="img/5.jpg"></li>
            <li><img src="img/10.gif" data-src="img/6.jpg"></li>
            <li><img src="img/10.gif" data-src="img/7.jpg"></li>
        </ul>
    <script src="js/intersectionObserver-lazyload.js"></script>
    <script>
    	let imgItems = [...document.querySelectorAll('img')];
    	lazyLoad(imgItems)
    </script>
    </body>
</html>
複製程式碼

原始碼

github地址

參考

圖片懶載入的前世今生

相關文章