利用原生JS實現懶加載lazyLoad的三種方法總結
前言
首先我們先搭建好頁面如下:
<style> * { padding: 0%; margin: 0%; } .contain img { width: 600px; height: 400px; } ul { list-style: none; } li { display: inline-block; } </style> <div class="contain"> <ul> <li><img data-src="./images/iu.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu1.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu2.png" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu3.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu4.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu5.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu6.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu7.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu8.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu9.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/iu10.jpg" src='./images/lazy.png' alt=""></li> <li><img data-src="./images/zzf_01.jpg" src='./images/lazy.png' alt=""></li> </ul> </div >
我們知道,圖片懶加載是在滾動條向下滾動時,才判斷圖片是否到達可視區域
於是我們需要在滾動監聽時判斷圖片是否即將顯示,所以我們需要將圖片的真實地址先隱藏起來,即采用自定義屬性 data-src 保存圖片的真實地址,當滾動條滾動到圖片能夠看到時再加載真實的地址.
下面我們來看第一個方法
Method 1: 高度對比
這裡我們采用 (元素距頂部的高度 – 頁面被卷去的高度 <= 瀏覽器可視區的高度) 來判斷是否符合我們想要的條件.這裡我們需要實時監聽頁面滾動時 圖片的高度變化
/** * 方法一 * 高度對比 */ let imgs = [...document.querySelectorAll('img')]; // 先獲取所有的圖片 window.addEventListener('scroll', function () { })
添加完事件後再繼續判斷 圖片是否達到要求,即
/** * 方法一 * 高度對比 */ let imgs = [...document.querySelectorAll('img')]; // 先獲取所有的圖片 window.addEventListener('scroll', function () { lazyLoad(imgs) }) function lazyLoad(imgs) { for (var i = 0; i < imgs.length; i++) { var height = imgs[i].offsetTop; // 圖片的距頂部的高度 var wheight = window.innerHeight; // 瀏覽器可視區的高度 var sheight = document.documentElement.scrollTop; // 頁面被卷去的高度 if (height - sheight <= wheight) { // 判斷圖片是否將要出現 imgs[i].src = imgs[i].dataset.src; // 出現後將自定義地址轉為真實地址 } } }
看起來還挺簡單的對吧? 不過我們還有更簡單的方法,如下:
Method 2: 使用getBoundingClientRect() 的API
先附上MDN 對getBoundingClientRect() 的解釋getBoundingClientRect()
我們可以通過 getBoundingClientRect().top來獲取元素距視口頂部的距離,於是我們就可以比較getBoundingClientRect().top 和 window.innerHeight 的值的關系來實現懶加載的效果
這裡使用瞭getAttribute() 和setAttribute() 屬性
/** * 方法二 * @params getBoundingClientRect() * 可視區API */ let imgs = [...document.querySelectorAll('img')]; window.addEventListener('scroll', function () { imgs.forEach(img => { //這裡其實和Method1的思想一樣,不過就是簡潔瞭一些 if (img.getBoundingClientRect().top < window.innerHeight) { let dataSrc = img.getAttribute(' data-src'); // 獲取 data-src 真實的地址 img.setAttribute('src', dataSrc); // 將 真實的地址 替換為 src屬性 console.log(img.src); } }) })
Method 3: 采用最新的 IntersectionObserver 構造函數
看過上面兩種方法,那你是否覺得懶加載還挺簡單的對吧?
沒錯,我們寫的代碼很少,看起來很簡單,但是我們忽略瞭一個重要的問題:
圖片替換為真實的地址之後,如果我們反復的拉動滾動條,會一直觸發 if()條件,
所以我在 Method2 方法裡給瞭一個 console.log(img.src);
目的就是為瞭讓你看到當有人持續不斷的拉動滾動條,會一直打印 console.log(img.src);
那我們怎麼去讓圖片真實地址加載完之後,不再觸發對它的頻繁操作呢?或者說怎麼優化遊覽器的性能呢?
好巧不巧,現在有瞭一個新增的構造函數,來解決我們的頻繁觸發條件語句的問題.
這個構造函數就是 IntersectionObserver
根據 MDN 上的解釋
- IntersectionObserver()構造器創建並返回一個IntersectionObserver對象。 如果指定rootMargin則會檢查其是否符合語法規定,檢查閾值以確保全部在0.0到1.0之間,並且閾值列表會按升序排列。如果閾值列表為空,則默認為一個[0.0]的數組。
- callback當元素可見比例超過指定閾值後,會調用一個回調函數,此回調函數接受兩個參數:
entries一個IntersectionObserverEntry對象的數組,每個被觸發的閾值,都或多或少與指定閾值有偏差。
observer被調用的IntersectionObserver實例。
這裡我們隻使用第一個參數 callback 這個回調函數
window.addEventListener('scroll', function () { // 首先我們先實例化這個構造函數 const observe = new IntersectionObserver(callback); // 然後寫我們需要處理業務的回調函數 callback const callback = entries => { console.log(entries); //我們先打印一下 entries 看看有什麼用 // 如下圖 }; }
window.addEventListener('scroll', function () { const observe = new IntersectionObserver(callback); // 然後寫我們需要處理業務的回調函數 callback const callback = entries => { // 我們發現它是個數組,於是 entries.forEach(ele => { console.log(ele); // 我們再打印一下元素,看看元素裡面有什麼 // 如下圖 }) }; }
我們找到瞭 isIntersecting: false 這個屬性,這個意思是 是否交叉,根據構造函數的意義我們得知,交叉可以理解為是否被觀察到
如果被觀察到, 那我們就讓他的真實地址替換為 它的 src 屬性 ,並且取消對它的觀察
/** * 方法三 * @params new IntersectionObserver(callback[,options]) * 觀察-->構造函數 */ window.addEventListener('scroll', function () { let imgs = [...document.querySelectorAll('.img')] const callback = entries => { // entries 是觀察的元素數組 entries.forEach(ele => { if (ele.isIntersecting) { // isIntersecting 是否被觀察到 const data_src = ele.target.getAttribute('data-src'); //這裡基本和 Method1/Method2一樣 ele.target.setAttribute('src', data_src); // ele.target 是目標元素 observe.unobserve(ele.target) // 真實地址替換後 取消對它的觀察 } }) }; const observe = new IntersectionObserver(callback); // 實例化 IntersectionObserver imgs.forEach(image => { observe.observe(image) // observe : 被調用的IntersectionObserver實例。給每個圖片添加觀察實例 }) }
這樣處理,我們就可以不再頻繁的去觸發 if() 條件語句
因為在圖片替換瞭真實地址後,我取消瞭對當前圖片的觀察,於是,當前圖片已經沒有事件再被觸發,所以這樣對瀏覽器的性能進行瞭極大的優化
總結
到此這篇關於利用原生JS實現懶加載lazyLoad的三種方法的文章就介紹到這瞭,更多相關JS實現懶加載lazyLoad內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 原生JS Intersection Observer API實現懶加載
- 可視化埋點平臺元素曝光采集intersectionObserver思路實踐
- Vue項目首屏性能優化組件實戰指南
- 分享12個Vue開發中的性能優化小技巧(實用!)
- ResizeObserver API使用示例詳解