<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
懶載入經常出現在前端面試中,是前端效能優化的常用技巧。懶載入也叫延遲載入,把非關鍵資源先不載入,等用到了再載入,將載入非關鍵資源的時間推遲,而加快頁面的初始載入時間。懶載入經常被用在圖片、視訊、音訊、JavaScript 檔案等資源載入上,本文主要討論圖片的懶載入。通過本文你能收穫:
圖片懶載入的原理是沒有在可視區域的圖片暫時不載入圖片,等進入可視區域後在載入圖片,這樣可以減少初始頁面載入的圖片數量而提升頁面載入速度。 圖片懶載入在提升頁面載入速度的同時也會伴隨使用者看其他未展示的圖片時會有等待時間;圖片載入顯示會伴有佈局抖動等問題。
圖片懶載入的關鍵是:判斷一個元素是否在可視區域。
HTMLImageElement 的 loading 屬性為一個字串,它的值會提示 使用者代理 告訴瀏覽器不在可視視口內的圖片該如何載入。這樣一來,通過推遲圖片載入僅讓其在需要的時候載入而非頁面初始載入時立刻載入,優化了頁面的載入。
lazy 告訴使用者代理推遲圖片載入直到瀏覽器認為其需要立即載入時才去載入。例如,如果使用者正在往下捲動頁面,值為 lazy 會導致圖片僅在馬上要出現在 可視視口中時開始載入。
<img src="xxx.jpg" loading="lazy" />
只設定一個屬性不用 JavaScript 控制程式碼是最簡單方便的方案,效能也是比較好的。
大部分主流瀏覽器都相容該屬性。
雖然整個方案簡單效能好,但問題也是最多的,所以很少使用這種方案。
該方案能粗略的實現圖片懶載入基本功能。
可視區域高度是 document.documentElement.clientHeight
,而可視區域的位置是在卷軸捲動位置 scrollTop
到 scrollTop+document.documentElement.clientHeight
之間。因此通過 image.offsetTop <= document.documentElement.clientHeight + document.documentElement.scrollTop
判斷圖片是否可以在可視區域內。
function lazyload() { var lazyImages = document.querySelectorAll(".lazyload"); lazyImages.forEach(function (image) { if ( image.offsetTop <= document.documentElement.clientHeight + document.documentElement.scrollTop) { image.src = image.getAttribute("data-src"); } }); }
新增卷軸監聽。
window.onscroll = function () { lazyload(); };
html結構。
<img src="./default.gif" class="lazyload" data-src="./photo-1.jpg" />
上面只是簡單的實現圖片懶載入,在實際開發中還要很多細節需要優化: 首先是相容性,這裡有兩個點涉及到相容性:document.documentElement.clientHeight
和document.documentElement.scrollTop
。 獲取瀏覽器視窗的內部高度方法有 window.innerHeight
、document.documentElement.clientHeight
。 window.innerHeight
相容性是 ie9+ 和其他主流瀏覽器。
document.documentElement.clientHeight
瀏覽器都支援。
獲取捲動位置方法有 window.pageYOffset
和 document.documentElement.scrollTop
。 window.pageYOffset
相容性是 ie9+ 和其他主流瀏覽器。
第二優化點是offsetTop。
offsetParent 元素有卷軸的情況下計算會不會有問題
HTMLElement.offsetTop 為唯讀屬性,它返回當前元素相對於其 offsetParent 元素的頂部內邊距的距離。 ——MDN
offsetTop 是相對其 offsetParent 元素的並不是相對瀏覽器視窗可視區域的。如果圖片元素有 offsetParent 那麼 offsetTop 是有偏差的。
function getBoundingClientTop(el) { let top = el.offsetTop; let parent = el.offsetParent; while (parent) { top += parent.offsetTop; parent = parent.offsetParent; } return top; }
第三優化點避免賦值 src 。 程式碼是通過 lazyload 類獲取需要懶載入的元素,這樣會把之前已經載入圖片的元素也獲取到了,而重複設定 src屬性。
function lazyload() { var lazyImages = document.querySelectorAll(".lazyload[data-src]"); lazyImages.forEach(function (image) { if ( getBoundingClientTop(image) <= document.documentElement.clientHeight + document.documentElement.scrollTop ) { image.src = image.getAttribute("data-src"); image.removeAttribute("data-src") } }); }
通過 lazyload 類並且有 data-src 來獲取元素,src 設定完後移除 data-src 屬性來避免重複設定 src 。
第四優化點 onscroll 是否新增防抖。 onscroll 常用的優化點是加入防抖來減少事件觸發的頻率,但這裡如果加了防抖,計算元素是否在可視區域內的精度就差很多,當捲動速度比較快的情況下載入反應不靈敏,這裡就要找平衡點。
第五優化點頁面中區域性的 div 捲動圖片懶載入。 除了整個頁面的捲動圖片懶載入,也有頁面中區域性捲動圖片懶載入,就需要給制定的有卷軸 dom 元素繫結onscroll 事件。
srcollDom.onscroll = function () { lazyload(); };
並且獲取圖片 top 是相對有卷軸 dom 元素
getBoundingClientTop(image)-getBoundingClientTop(srcollDom) <= srcollDom.clientHeight + srcollDom.scrollTop
第六優化點載入圖片的時間點提前。 程式碼中是圖片元素進入可視區域後才載入圖片,使用者就需要等待一段時間才能看到圖片顯示出來,如果把圖片載入時間提前,圖片元素距離可視區域一定範圍內就載入圖片,那麼使用者等待時間就會減少一些。
相容性好,各個環節可以控制。
效能相對不是很好,捲動事件頻繁觸發,並且獲取元素的位置資訊,可能會強行觸發重排和重繪導致一定的效能消耗。
大致思路和方案二一樣只是把獲取圖片元素 offsetTop
改成 getBoundingClientRect
方法獲取離可視區頂端的距離。比方案一要簡單一點,缺點也和方案一一樣。
該方案是通過 IntersectionObserver 來判斷圖片元素是否在可視區域內。
IntersectionObserver() 構造器建立並返回一個 IntersectionObserver 物件。如果指定 rootMargin 則會檢查其是否符合語法規定,檢查閾值以確保全部在 0.0 到 1.0 之間,並且閾值列表會按升序排列。如果閾值列表為空,則預設為一個 [0.0] 的陣列。 —— MDN
完全沒看懂mdn的這段解釋,簡單說就是
IntersectionObserver 介面提供了一種非同步觀察目標元素與祖先元素或頂級檔案 viewport 的交集中的變化的方法。祖先元素與視窗viewport被稱為根(root)。
var images = document.querySelectorAll(".lazyload"); var io = new IntersectionObserver( function (entries) { entries.forEach((item) => { // isIntersecting是一個Boolean值,判斷目標元素當前是否可見 if (item.isIntersecting) { item.target.src = item.target.dataset.src; // 圖片載入後即停止監聽該元素 io.unobserve(item.target); } }); } ); images.forEach(function(image){ io.observe(image) })
IntersectionObserver 的監聽對於頁面區域性卷軸也是有效的,不用再單獨對區域性卷軸進行處理。 而提前載入圖片通過設定 rootMargin 來擴大監聽區域。
var images = document.querySelectorAll(".lazyload"); var io = new IntersectionObserver( function (entries) { entries.forEach((item) => { // isIntersecting是一個Boolean值,判斷目標元素當前是否可見 if (item.isIntersecting) { item.target.src = item.target.dataset.src; // 圖片載入後即停止監聽該元素 io.unobserve(item.target); } }); }, { root: null, rootMargin: "0px 0px 300px 0px", } ); images.forEach(function(image){ io.observe(image); })
在一些低版本瀏覽器中還存在一些問題。
效能好,簡單。
低版本瀏覽器 IntersectionObserver 存在問題,不支援 IE。
佈局抖動是因為開始圖片沒有寬高,內容顯示出來後有了寬高導致位置變動。帶來的影響主要是使用者體驗不好,使用者的注意力已經鎖定了某個區域準備閱讀,突然那個區域下移了,中斷閱讀而重新定位。可以直接在 img 標籤上設定要載入圖片的寬高。
<img src="blank.gif" data-src="normal.jpg" style="width:800px;height:600px;" />
解決問題:方案解決的問題範圍是圖片寬高固定的情況,在響應式環境圖片寬高不確定下不適用。
使用者體驗:img的預設佔點陣圖是一個loading或是灰色背景,圖片還沒載入的體驗。
雖然響應式下圖片的寬高會變,但是圖片的寬高比是不變的,圖片的寬高比變了圖片也就變形了。所以 img 標籤設定圖片寬高比,就能根據不同檢視的寬度算出不同高度。 先建立一個寬高比為 5:1 的 div。
<div style="padding-bottom: 20%;background-color: green;"></div>
padding 為百分比是相對自身寬度的百分比。 然後再建立了一個寬高比為 5:1 的 img。
<div style="padding-bottom: 20%;position: relative;"> <img style="position:absolute;width: 100%;height:100%"> </div>
這樣就能適應響應式的寬度改變,這種方式叫 Aspect Ratio Boxes。 佔點陣圖片可以設定成原圖片的小尺寸圖片,被放大後圖片變模糊,這樣開始載入小圖片但圖片的輪廓出現,後面在載入大圖片顯示清晰,給使用者的體驗是圖片開始就在載入,然後載入完成就變清晰了。 img 標籤 srcset 屬性是處理響應式圖片的。懶載入中可以設定 data-srcset 來延遲修改 srcset 屬性。
<img>
標籤中的 src 屬性攜帶的仍然是原始大小的圖片確保了站外 SEO、社會化分享、RSS 等不會讀不到原圖。Aspect Ratio Boxes 方式使佔點陣圖片適應響應式,srcset 屬性存放了一張原圖的小尺寸縮圖阻止 src 原圖的載入而載入縮圖優化載入體驗,最後延遲將 data-srcset 的值賦值到 srcset 中。
以上就是前端JS圖片懶載入原理方案詳解的詳細內容,更多關於JS圖片懶載入原理的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45