文章首次發表在 我的博客
當咱們向下滾動的時候圖片資源才被請求到,這也就是咱們本次要實現的效果,進入頁面的時候,只請求可視區域的圖片資源這也就是懶加載。html
好比咱們加載一個頁面,這個頁面很長很長,長到咱們的瀏覽器可視區域裝不下,那麼懶加載就是優先加載可視區域的內容,其餘部分等進入了可視區域在加載。vue
這個功能很是常見,你打開淘寶的首頁,向下滾動,就會看到會有圖片不斷的加載;你在百度中搜索圖片,結果確定成千上萬條,不可能全部的都一會兒加載出來的,很重要的緣由就是會有性能問題。你能夠在Network中查看,在頁面滾動的時候,會看到圖片一張張加載出來。node
懶加載是一種網頁性能優化的方式,它能極大的提高用戶體驗。就好比說圖片,圖片一直是影響網頁性能的主要元兇,如今一張圖片超過幾兆已是很常常的事了。若是每次進入頁面就請求全部的圖片資源,那麼可能等圖片加載出來用戶也早就走了。因此,咱們須要懶加載,進入頁面的時候,只請求可視區域的圖片資源。git
總結出來就兩個點:github
1.所有加載的話會影響用戶體驗express
2.浪費用戶的流量,有些用戶並不像所有看完,所有加載會耗費大量流量。npm
圖片的標籤是 img
標籤,圖片的來源主要是 src屬性,瀏覽器是否發起加載圖片的請求是根據是否有src屬性決定的。api
因此能夠從 img
標籤的 src屬性入手,在沒進到可視區域的時候,就先不給 img 標籤的 src屬性賦值。瀏覽器
實現效果圖:性能優化
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> div { display: flex; flex-direction: column; } img { width: 100%; height: 300px; } </style> </head> <body> <div> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg"> <img data-src="https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg"> </div> </body> </html>
const imgs = [...document.getElementsByTagName('img')]; let n = 0; lazyload(); function throttle(fn, wait) { let timer = null; return function(...args) { if(!timer) { timer = setTimeout(() => { timer = null; fn.apply(this, args) }, wait) } } } function lazyload() { var innerHeight = window.innerHeight; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; for(let i = n; i < imgs.length; i++) { if(imgs[i].offsetTop < innerHeight + scrollTop) { imgs[i].src = imgs[i].getAttribute("data-src"); n = i + 1; } } } window.addEventListener('scroll', throttle(lazyload, 200));
可能會存在下面幾個問題:
getboundingclientrect
獲取Intersection Observer API提供了一種異步觀察目標元素與祖先元素或頂級文檔viewport的交集中的變化的方法。
建立一個 IntersectionObserver對象,並傳入相應參數和回調用函數,該回調函數將會在目標(target)元素和根(root)元素的交集大小超過閾值(threshold)規定的大小時候被執行。
var observer = new IntersectionObserver(callback, options);
IntersectionObserver是瀏覽器原生提供的構造函數,接受兩個參數:callback是可見性變化時的回調函數(即目標元素出如今root選項指定的元素中可見時,回調函數將會被執行),option是配置對象(該參數可選)。
返回的 observer
是一個觀察器實例。實例的 observe 方法能夠指定觀察哪一個DOM節點。
具體的用法能夠 查看 MDN文檔
const imgs = [...document.getElementsByTagName('img')]; // 當監聽的元素進入可視範圍內的會觸發回調 if(IntersectionObserver) { // 建立一個 intersection observer let lazyImageObserver = new IntersectionObserver((entries, observer) => { entries.forEach((entry, index) => { let lazyImage = entry.target; // 相交率,默認是相對於瀏覽器視窗 if(entry.intersectionRatio > 0) { lazyImage.src = lazyImage.getAttribute('data-src'); // 當前圖片加載完以後須要去掉監聽 lazyImageObserver.unobserve(lazyImage); } }) }) for(let i = 0; i < imgs.length; i++) { lazyImageObserver.observe(imgs[i]); } }
下面的api來自官網自定義指令:
指令鉤子函數會被傳入如下參數:
binding:一個對象,包含如下 property:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> <style> img { width: 100%; height: 300px; } </style> </head> <body> <div id="app"> <p v-for="item in imgs" :key="item"> <img v-lazyload="item"> </p> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue"></script> <script> Vue.directive("lazyload", { // 指令的定義 bind: function(el, binding) { let lazyImageObserver = new IntersectionObserver((entries, observer) => { entries.forEach((entry, index) => { let lazyImage = entry.target; // 相交率,默認是相對於瀏覽器視窗 if(entry.intersectionRatio > 0) { lazyImage.src = binding.value; // 當前圖片加載完以後須要去掉監聽 lazyImageObserver.unobserve(lazyImage); } }) }) lazyImageObserver.observe(el); }, }); var app = new Vue({ el: "#app", data: { imgs: [ 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657907683.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657913523.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657925550.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657930289.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657934750.jpeg', 'https://cdn.suisuijiang.com/ImageMessage/5adad39555703565e79040fa_1590657918315.jpeg', ] }, }); </script> </html>