日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁技術(shù)文章
文章詳情頁

前端JS圖片懶加載原理方案詳解

瀏覽:343日期:2022-06-01 11:07:25
目錄
  • 背景
  • 原理
  • 方案
    • 方案一:img的loading屬性設(shè)為“lazy”
      • 使用方法
      • 優(yōu)點(diǎn)
      • 兼容性
      • 缺點(diǎn)
    • 方案二:通過offsetTop來計(jì)算是否在可視區(qū)域內(nèi)
      • 優(yōu)化
      • 優(yōu)點(diǎn)
      • 缺點(diǎn)
    • 方案三:通過getBoundingClientRect來計(jì)算是否在可視區(qū)域內(nèi)
      • 方案四:使用IntersectionObserver來判斷是否在可視區(qū)域內(nèi)
        • 兼容性
        • 優(yōu)點(diǎn)
        • 缺點(diǎn)
    • 問題
      • 布局抖動(dòng)
        • 響應(yīng)式圖片
          • SEO不友好
          • 插件

            背景

            懶加載經(jīng)常出現(xiàn)在前端面試中,是前端性能優(yōu)化的常用技巧。懶加載也叫延遲加載,把非關(guān)鍵資源先不加載,等用到了再加載,將加載非關(guān)鍵資源的時(shí)間推遲,而加快頁面的初始加載時(shí)間。懶加載經(jīng)常被用在圖片、視頻、音頻、JavaScript 文件等資源加載上,本文主要討論圖片的懶加載。通過本文你能收獲:

            • 圖片懶加載的原理
            • 實(shí)現(xiàn)圖片懶加載的四種方案的原理以及優(yōu)缺點(diǎn)
            • 圖片懶加載的一些優(yōu)化

            原理

            圖片懶加載的原理是沒有在可視區(qū)域的圖片暫時(shí)不加載圖片,等進(jìn)入可視區(qū)域后在加載圖片,這樣可以減少初始頁面加載的圖片數(shù)量而提升頁面加載速度。 圖片懶加載在提升頁面加載速度的同時(shí)也會(huì)伴隨用戶看其他未展示的圖片時(shí)會(huì)有等待時(shí)間;圖片加載顯示會(huì)伴有布局抖動(dòng)等問題。

            方案

            圖片懶加載的關(guān)鍵是:判斷一個(gè)元素是否在可視區(qū)域。

            方案一:img的loading屬性設(shè)為“lazy”

            HTMLImageElement 的 loading 屬性為一個(gè)字符串,它的值會(huì)提示 用戶代理 告訴瀏覽器不在可視視口內(nèi)的圖片該如何加載。這樣一來,通過推遲圖片加載僅讓其在需要的時(shí)候加載而非頁面初始載入時(shí)立刻加載,優(yōu)化了頁面的載入。

            lazy 告訴用戶代理推遲圖片加載直到瀏覽器認(rèn)為其需要立即加載時(shí)才去加載。例如,如果用戶正在往下滾動(dòng)頁面,值為 lazy 會(huì)導(dǎo)致圖片僅在馬上要出現(xiàn)在 可視視口中時(shí)開始加載。

            使用方法

            <img src="xxx.jpg" loading="lazy" />  

            優(yōu)點(diǎn)

            只設(shè)置一個(gè)屬性不用 JavaScript 控制代碼是最簡(jiǎn)單方便的方案,性能也是比較好的。

            兼容性

            大部分主流瀏覽器都兼容該屬性。

            缺點(diǎn)

            雖然整個(gè)方案簡(jiǎn)單性能好,但問題也是最多的,所以很少使用這種方案。

            • 前面提到圖片懶加載用戶看其他未展示的圖片時(shí)會(huì)有等待時(shí)間,一般會(huì)設(shè)置一個(gè)默認(rèn)圖片,這種方案不能設(shè)置默認(rèn)圖片
            • 圖片的加載數(shù)量和圖片的布局、可視區(qū)域尺寸有關(guān),難以控制
            • 圖片的加載順序也難以控制

            該方案能粗略的實(shí)現(xiàn)圖片懶加載基本功能。

            方案二:通過offsetTop來計(jì)算是否在可視區(qū)域內(nèi)

            可視區(qū)域高度是 document.documentElement.clientHeight ,而可視區(qū)域的位置是在滾動(dòng)條滾動(dòng)位置 scrollTopscrollTop+document.documentElement.clientHeight之間。因此通過 image.offsetTop <= document.documentElement.clientHeight + document.documentElement.scrollTop 判斷圖片是否可以在可視區(qū)域內(nèi)。

              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");  }});      }

            添加滾動(dòng)條監(jiān)聽。

              window.onscroll = function () {lazyload();};

            html結(jié)構(gòu)。

             <img src="./default.gif" data-src="./photo-1.jpg" />

            優(yōu)化

            上面只是簡(jiǎn)單的實(shí)現(xiàn)圖片懶加載,在實(shí)際開發(fā)中還要很多細(xì)節(jié)需要優(yōu)化: 首先是兼容性,這里有兩個(gè)點(diǎn)涉及到兼容性:document.documentElement.clientHeightdocument.documentElement.scrollTop 。 獲取瀏覽器窗口的內(nèi)部高度方法有 window.innerHeightdocument.documentElement.clientHeightwindow.innerHeight兼容性是 ie9+ 和其他主流瀏覽器。

            document.documentElement.clientHeight 瀏覽器都支持。

            獲取滾動(dòng)位置方法有 window.pageYOffsetdocument.documentElement.scrollTopwindow.pageYOffset 兼容性是 ie9+ 和其他主流瀏覽器。

            第二優(yōu)化點(diǎn)是offsetTop。

            offsetParent 元素有滾動(dòng)條的情況下計(jì)算會(huì)不會(huì)有問題

            HTMLElement.offsetTop 為只讀屬性,它返回當(dāng)前元素相對(duì)于其 offsetParent 元素的頂部?jī)?nèi)邊距的距離。 ——MDN

            offsetTop 是相對(duì)其 offsetParent 元素的并不是相對(duì)瀏覽器窗口可視區(qū)域的。如果圖片元素有 offsetParent 那么 offsetTop 是有偏差的。

                  function getBoundingClientTop(el) {let top = el.offsetTop;let parent = el.offsetParent;while (parent) {  top += parent.offsetTop;  parent = parent.offsetParent;}return top;      }

            第三優(yōu)化點(diǎn)避免賦值 src 。 代碼是通過 lazyload 類獲取需要懶加載的元素,這樣會(huì)把之前已經(jīng)加載圖片的元素也獲取到了,而重復(fù)設(shè)置 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 設(shè)置完后移除 data-src 屬性來避免重復(fù)設(shè)置 src 。

            第四優(yōu)化點(diǎn) onscroll 是否添加防抖。 onscroll 常用的優(yōu)化點(diǎn)是加入防抖來減少事件觸發(fā)的頻率,但這里如果加了防抖,計(jì)算元素是否在可視區(qū)域內(nèi)的精度就差很多,當(dāng)滾動(dòng)速度比較快的情況下加載反應(yīng)不靈敏,這里就要找平衡點(diǎn)。

            第五優(yōu)化點(diǎn)頁面中局部的 div 滾動(dòng)圖片懶加載。 除了整個(gè)頁面的滾動(dòng)圖片懶加載,也有頁面中局部滾動(dòng)圖片懶加載,就需要給制定的有滾動(dòng)條 dom 元素綁定onscroll 事件。

                srcollDom.onscroll = function () {lazyload();      };

            并且獲取圖片 top 是相對(duì)有滾動(dòng)條 dom 元素

            getBoundingClientTop(image)-getBoundingClientTop(srcollDom) <= srcollDom.clientHeight + srcollDom.scrollTop

            第六優(yōu)化點(diǎn)加載圖片的時(shí)間點(diǎn)提前。 代碼中是圖片元素進(jìn)入可視區(qū)域后才加載圖片,用戶就需要等待一段時(shí)間才能看到圖片顯示出來,如果把圖片加載時(shí)間提前,圖片元素距離可視區(qū)域一定范圍內(nèi)就加載圖片,那么用戶等待時(shí)間就會(huì)減少一些。

            優(yōu)點(diǎn)

            兼容性好,各個(gè)環(huán)節(jié)可以控制。

            缺點(diǎn)

            性能相對(duì)不是很好,滾動(dòng)事件頻繁觸發(fā),并且獲取元素的位置信息,可能會(huì)強(qiáng)行觸發(fā)重排和重繪導(dǎo)致一定的性能消耗。

            方案三:通過getBoundingClientRect來計(jì)算是否在可視區(qū)域內(nèi)

            大致思路和方案二一樣只是把獲取圖片元素 offsetTop 改成 getBoundingClientRect 方法獲取離可視區(qū)頂端的距離。比方案一要簡(jiǎn)單一點(diǎn),缺點(diǎn)也和方案一一樣。

            方案四:使用IntersectionObserver來判斷是否在可視區(qū)域內(nèi)

            該方案是通過 IntersectionObserver 來判斷圖片元素是否在可視區(qū)域內(nèi)。

            IntersectionObserver() 構(gòu)造器創(chuàng)建并返回一個(gè) IntersectionObserver 對(duì)象。如果指定 rootMargin 則會(huì)檢查其是否符合語法規(guī)定,檢查閾值以確保全部在 0.0 到 1.0 之間,并且閾值列表會(huì)按升序排列。如果閾值列表為空,則默認(rèn)為一個(gè) [0.0] 的數(shù)組。 —— MDN

            完全沒看懂mdn的這段解釋,簡(jiǎn)單說就是

            IntersectionObserver 接口提供了一種異步觀察目標(biāo)元素與祖先元素或頂級(jí)文檔 viewport 的交集中的變化的方法。祖先元素與視窗viewport被稱為根(root)。

                  var images = document.querySelectorAll(".lazyload");      var io = new IntersectionObserver(function (entries) {  entries.forEach((item) => {    // isIntersecting是一個(gè)Boolean值,判斷目標(biāo)元素當(dāng)前是否可見    if (item.isIntersecting) {      item.target.src = item.target.dataset.src;      // 圖片加載后即停止監(jiān)聽該元素      io.unobserve(item.target);    }  });}      );      images.forEach(function(image){io.observe(image)      })

            IntersectionObserver 的監(jiān)聽對(duì)于頁面局部滾動(dòng)條也是有效的,不用再單獨(dú)對(duì)局部滾動(dòng)條進(jìn)行處理。 而提前加載圖片通過配置 rootMargin 來擴(kuò)大監(jiān)聽區(qū)域。

                  var images = document.querySelectorAll(".lazyload");      var io = new IntersectionObserver(function (entries) {  entries.forEach((item) => {    // isIntersecting是一個(gè)Boolean值,判斷目標(biāo)元素當(dāng)前是否可見    if (item.isIntersecting) {      item.target.src = item.target.dataset.src;      // 圖片加載后即停止監(jiān)聽該元素      io.unobserve(item.target);    }  });},{  root: null,  rootMargin: "0px 0px 300px 0px",}      );      images.forEach(function(image){io.observe(image);      })

            兼容性

            在一些低版本瀏覽器中還存在一些問題。

            優(yōu)點(diǎn)

            性能好,簡(jiǎn)單。

            缺點(diǎn)

            低版本瀏覽器 IntersectionObserver 存在問題,不支持 IE。

            問題

            布局抖動(dòng)

            布局抖動(dòng)是因?yàn)殚_始圖片沒有寬高,內(nèi)容顯示出來后有了寬高導(dǎo)致位置變動(dòng)。帶來的影響主要是用戶體驗(yàn)不好,用戶的注意力已經(jīng)鎖定了某個(gè)區(qū)域準(zhǔn)備閱讀,突然那個(gè)區(qū)域下移了,中斷閱讀而重新定位。可以直接在 img 標(biāo)簽上設(shè)置要加載圖片的寬高。

            <img src="blank.gif" data-src="normal.jpg" />

            解決問題:方案解決的問題范圍是圖片寬高固定的情況,在響應(yīng)式環(huán)境圖片寬高不確定下不適用。

            用戶體驗(yàn):img的默認(rèn)占位圖是一個(gè)loading或是灰色背景,圖片還沒加載的體驗(yàn)。

            響應(yīng)式圖片

            雖然響應(yīng)式下圖片的寬高會(huì)變,但是圖片的寬高比是不變的,圖片的寬高比變了圖片也就變形了。所以 img 標(biāo)簽設(shè)定圖片寬高比,就能根據(jù)不同視圖的寬度算出不同高度。 先創(chuàng)建一個(gè)寬高比為 5:1 的 div。

               <div></div>

            padding 為百分比是相對(duì)自身寬度的百分比。 然后再創(chuàng)建了一個(gè)寬高比為 5:1 的 img。

                <div><img>      </div>

            這樣就能適應(yīng)響應(yīng)式的寬度改變,這種方式叫 Aspect Ratio Boxes。 占位圖片可以設(shè)置成原圖片的小尺寸圖片,被放大后圖片變模糊,這樣開始加載小圖片但圖片的輪廓出現(xiàn),后面在加載大圖片顯示清晰,給用戶的體驗(yàn)是圖片開始就在加載,然后加載完成就變清晰了。 img 標(biāo)簽 srcset 屬性是處理響應(yīng)式圖片的。懶加載中可以設(shè)置 data-srcset 來延遲修改 srcset 屬性。

            SEO不友好

            <img> 標(biāo)簽中的 src 屬性攜帶的仍然是原始大小的圖片確保了站外 SEO、社會(huì)化分享、RSS 等不會(huì)讀不到原圖。Aspect Ratio Boxes 方式使占位圖片適應(yīng)響應(yīng)式,srcset 屬性存放了一張?jiān)瓐D的小尺寸縮略圖阻止 src 原圖的加載而加載縮略圖優(yōu)化加載體驗(yàn),最后延遲將 data-srcset 的值賦值到 srcset 中。

            插件

            • lazyload.js 是 IntersectionObserver 方式,而且當(dāng)瀏覽器不支持 IntersectionObserver 的時(shí)候就直接加載圖片,沒有延遲加載的功能。
            • vue-lazyload 使用 IntersectionObserver 和 getBoundingClientRect 方式,默認(rèn) getBoundingClientRect 方式懶加載,里面的一些封裝細(xì)節(jié)有很多有意思的地方,不止綁定了 onscroll 事件還綁定了 'onwheel'、'onmousewheel'、'onresize'、 'onanimationend'、'ontransitionend'、'ontouchmove'問什么要綁定這么多事件,插件為什么默認(rèn) getBoundingClientRect 方式而不用 IntersectionObserver 方式,待下回分解。
            • react-lazyload 只用了 getBoundingClientRect 方式,里面的封裝細(xì)節(jié)也很有意思,待下回分解。

            以上就是前端JS圖片懶加載原理方案詳解的詳細(xì)內(nèi)容,更多關(guān)于JS圖片懶加載原理的資料請(qǐng)關(guān)注其它相關(guān)文章!

            標(biāo)簽: JavaScript
            日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
            国产精久久久| 日韩精品亚洲专区在线观看| 国产中文在线播放| 深夜福利一区| 国产日韩欧美一区在线| 久久亚州av| 三级精品视频| 91精品福利| 免费久久精品视频| 日本欧美韩国一区三区| 成人午夜网址| 欧美日韩在线二区| 国产香蕉精品| 亚洲欧美日韩国产综合精品二区| 国产一区二区三区四区大秀| 日韩高清在线不卡| 久久国际精品| 超碰成人av| 日韩毛片在线| 久久99伊人| 日本亚洲不卡| 国产精品激情| 日韩成人高清| 视频一区国产视频| 69堂免费精品视频在线播放| 国产一区二区三区视频在线| 精品一区亚洲| 视频精品一区| 久久久亚洲欧洲日产| 99国产精品免费视频观看| 男女男精品网站| 国产美女久久| av资源中文在线天堂| 欧美日韩国产一区精品一区| 亚洲+小说+欧美+激情+另类| 久久成人高清| 不卡av一区二区| 日韩欧美三区| 国产一区二区三区探花| 中文亚洲免费| 国产极品嫩模在线观看91精品| 精品日韩视频| 亚洲精品影视| 国产一区二区色噜噜| 99国产精品视频免费观看一公开| 日韩av一级片| 国产一区观看| 啪啪亚洲精品| 久久精品动漫| 国产伦精品一区二区三区千人斩 | 免费在线观看视频一区| 国产精品尤物| 国产亚洲亚洲| 国产精品成久久久久| 国产精品呻吟| 国产成年精品| 日韩一区免费| 九九综合在线| 国产精品黄色片| 日韩视频免费| 欧美成人精品午夜一区二区| 亚洲一区久久| 三级在线看中文字幕完整版| 亚洲精品黄色| 91精品精品| 国产精品草草| 亚洲欧美日韩国产| 美女av在线免费看| 国产亚洲一卡2卡3卡4卡新区| 婷婷亚洲综合| 精品视频97| 四虎成人精品一区二区免费网站 | 国产综合婷婷| 国产欧美日韩在线观看视频| 香蕉久久99| 黄色精品视频| 日韩国产欧美三级| 在线综合亚洲| 久久精品1区| 免费在线亚洲| 日韩精品免费观看视频| 在线视频观看日韩| 成人国产精品久久| 日韩av成人高清| 在线免费观看亚洲| 激情婷婷综合| 国产黄大片在线观看| 国产乱码精品一区二区三区亚洲人| 91九色精品| av高清不卡| 三上亚洲一区二区| 欧美aaaaaa午夜精品| 日本午夜精品一区二区三区电影| 久久香蕉精品| 国产亚洲精品自拍| 欧美日韩国产在线观看网站| 中文字幕在线看片| 久久不见久久见国语| 亚洲91在线| 一区二区亚洲视频| 老牛影视一区二区三区 | 伊伊综合在线| 另类欧美日韩国产在线| 日韩精品第一| 视频一区二区三区在线| 在线一区电影| 九一国产精品| 秋霞影院一区二区三区| 中文字幕在线看片| 亚洲三级欧美| 国产另类在线| 国产人成精品一区二区三| 日本aⅴ精品一区二区三区| 综合激情一区| 日韩一区二区三区高清在线观看| 中文不卡在线| 亚洲开心激情| 免费观看在线综合| 三级亚洲高清视频| 亚洲精品高潮| 日本色综合中文字幕| 日韩中文字幕视频网| 色综合视频一区二区三区日韩| 中文字幕一区二区三区四区久久| 天海翼精品一区二区三区| 日韩一区中文| 国产精品任我爽爆在线播放| 精品视频亚洲| 色爱av综合网| 黄色亚洲免费| 男人的天堂久久精品| 日本午夜精品一区二区三区电影| 日本在线视频一区二区| 欧美一区久久| 麻豆久久久久久久| 日韩av自拍| 欧美日韩亚洲在线观看| 99riav1国产精品视频| 亚洲精品观看| 国产精品va| 日韩欧美综合| 亚洲黄页一区| 日本va欧美va瓶| 麻豆视频一区二区| 精品免费av在线| 模特精品在线| 国产精品日韩精品中文字幕| 老牛国内精品亚洲成av人片| 91综合视频| 亚洲综合不卡| 国产亚洲一卡2卡3卡4卡新区| 国模精品一区| 欧美成人日韩| 亚洲va久久久噜噜噜久久| 国产日韩亚洲欧美精品| 在线天堂中文资源最新版| 国产真实久久| 亚洲精品在线二区| 成人午夜毛片| 久久xxxx| 国产精品久久亚洲不卡| 亚洲人成在线网站| 夜夜嗨网站十八久久| 91精品国产自产观看在线| 日韩成人精品一区| 亚洲一区二区三区免费在线观看| **爰片久久毛片| 久久久成人网| 日本aⅴ免费视频一区二区三区| 成人午夜在线| 久久都是精品| 久久不见久久见中文字幕免费| 999久久久免费精品国产| 综合激情一区| 国产成人久久精品一区二区三区| 欧美天堂视频| 欧美在线综合| 欧美aa在线视频| 99香蕉国产精品偷在线观看 | 男女男精品网站| 久久久国产精品入口麻豆| 欧美日韩在线二区| 欧美亚洲三区| 宅男在线一区| 亚洲欧美在线专区| 在线天堂中文资源最新版| 亚洲精品黄色| 亚洲精品在线影院| 人人爱人人干婷婷丁香亚洲| 香蕉视频亚洲一级| 日韩高清电影一区| 国产精品专区免费| 日韩激情一二三区| 欧美日中文字幕| 欧美黄色一区二区| 久久99伊人| 日韩欧美另类一区二区| 久久精品xxxxx| 欧美日韩99| 亚洲一区二区网站|