整合營(yíng)銷(xiāo)服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢(xún)熱線(xiàn):

          前端優(yōu)化方法:懶加載

          前端優(yōu)化方法:懶加載

          為 `src` 賦值成一個(gè)通用的預(yù)覽圖,下拉時(shí)候再動(dòng)態(tài)賦值成正式的圖片。

          `preview.png`是預(yù)覽圖片,比較小,加載很快,而且很多圖片都共用這個(gè)`preview.png`,加載一次即可。

          待頁(yè)面下拉,圖片顯示出來(lái)時(shí),再去替換`src`為`data-realsrc`的值。

          <img src="preview.png" data-realsrc="abc.png"/>

          這里為何要用`data-`開(kāi)頭的屬性值?

          所有 HTML 中自定義的屬性,都應(yīng)該用`data-`開(kāi)頭,因?yàn)閌data-`開(kāi)頭的屬性瀏覽器渲染的時(shí)候會(huì)忽略掉,提高渲染性能。


          加載


          什么是懶加載

          懶加載其實(shí)就是延遲加載,是一種對(duì)網(wǎng)頁(yè)性能優(yōu)化可方式,比如當(dāng)訪(fǎng)問(wèn)一個(gè)頁(yè)面的時(shí)候,優(yōu)先顯示可視區(qū)域的圖片而不一次性加載所有圖片,當(dāng)需要顯示的時(shí)候再發(fā)送圖片請(qǐng)求,避免打開(kāi)網(wǎng)頁(yè)時(shí)加載過(guò)多資源。

          什么時(shí)候用懶加載

          當(dāng)頁(yè)面中需要一次性載入很多圖片的時(shí)候,往往都是需要用懶加載的。

          懶加載原理

          我們都知道HTML中的 <img>標(biāo)簽是代表文檔中的一個(gè)圖像。。說(shuō)了個(gè)廢話(huà)。。

          <img>標(biāo)簽有一個(gè)屬性是 src,用來(lái)表示圖像的URL,當(dāng)這個(gè)屬性的值不為空時(shí),瀏覽器就會(huì)根據(jù)這個(gè)值發(fā)送請(qǐng)求。如果沒(méi)有 src屬性,就不會(huì)發(fā)送請(qǐng)求。

          嗯?貌似這點(diǎn)可以利用一下?

          我先不設(shè)置 src,需要的時(shí)候再設(shè)置?

          nice,就是這樣。

          我們先不給 <img>設(shè)置 src,把圖片真正的URL放在另一個(gè)屬性 data-src中,在需要的時(shí)候也就是圖片進(jìn)入可視區(qū)域的之前,將URL取出放到 src中。

          實(shí)現(xiàn)


          HTML結(jié)構(gòu)

          <div class="container">
           <div class="img-area">
             <img class="my-photo" alt="loading" data-src="./img/img1.png">
           </div>
           <div class="img-area">
             <img class="my-photo" alt="loading" data-src="./img/img2.png">
           </div>
           <div class="img-area">
             <img class="my-photo" alt="loading" data-src="./img/img3.png">
           </div>
           <div class="img-area">
             <img class="my-photo" alt="loading" data-src="./img/img4.png">
           </div>
           <div class="img-area">
             <img class="my-photo" alt="loading" data-src="./img/img5.png">
           </div>
          </div>

          仔細(xì)觀察一下, <img>標(biāo)簽此時(shí)是沒(méi)有 src屬性的,只有 alt和 data-src屬性。

          alt 屬性是一個(gè)必需的屬性,它規(guī)定在圖像無(wú)法顯示時(shí)的替代文本。 data-* 全局屬性:構(gòu)成一類(lèi)名稱(chēng)為自定義數(shù)據(jù)屬性的屬性,可以通過(guò) HTMLElement.dataset來(lái)訪(fǎng)問(wèn)。

          如何判斷元素是否在可視區(qū)域

          方法一

          網(wǎng)上看到好多這種方法,稍微記錄一下。

          1. 通過(guò) document.documentElement.clientHeight獲取屏幕可視窗口高度
          2. 通過(guò) document.documentElement.scrollTop獲取瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動(dòng)條滾動(dòng)的距離
          3. 通過(guò) element.offsetTop獲取元素相對(duì)于文檔頂部的距離

          然后判斷②-③<①是否成立,如果成立,元素就在可視區(qū)域內(nèi)。

          方法二(推薦)

          通過(guò) getBoundingClientRect()方法來(lái)獲取元素的大小以及位置,MDN上是這樣描述的:

          The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.

          這個(gè)方法返回一個(gè)名為 ClientRect的 DOMRect對(duì)象,包含了 top、 right、 botton、 left、 width、 height這些值。

          MDN上有這樣一張圖:

          可以看出返回的元素位置是相對(duì)于左上角而言的,而不是邊距。

          我們思考一下,什么情況下圖片進(jìn)入可視區(qū)域。

          假設(shè) constbound=el.getBoundingClientRect();來(lái)表示圖片到可視區(qū)域頂部距離; 并設(shè) constclientHeight=window.innerHeight;來(lái)表示可視區(qū)域的高度。

          隨著滾動(dòng)條的向下滾動(dòng), bound.top會(huì)越來(lái)越小,也就是圖片到可視區(qū)域頂部的距離越來(lái)越小,當(dāng) bound.top===clientHeight時(shí),圖片的上沿應(yīng)該是位于可視區(qū)域下沿的位置的臨界點(diǎn),再滾動(dòng)一點(diǎn)點(diǎn),圖片就會(huì)進(jìn)入可視區(qū)域。

          也就是說(shuō),在 bound.top<=clientHeight時(shí),圖片是在可視區(qū)域內(nèi)的。

          我們這樣判斷:

          function isInSight(el) {
           const bound=el.getBoundingClientRect();
           const clientHeight=window.innerHeight;
           //如果只考慮向下滾動(dòng)加載
           //const clientWidth=window.innerWeight;
           return bound.top <=clientHeight + 100;
          }

          這里有個(gè)+100是為了提前加載。

          加載圖片

          頁(yè)面打開(kāi)時(shí)需要對(duì)所有圖片進(jìn)行檢查,是否在可視區(qū)域內(nèi),如果是就加載。

          function checkImgs() {
           const imgs=document.querySelectorAll('.my-photo');
           Array.from(imgs).forEach(el=> {
             if (isInSight(el)) {
               loadImg(el);
             }
           })
          }
          
          function loadImg(el) {
           if (!el.src) {
             const source=el.dataset.src;
             el.src=source;
           }
          }

          這里應(yīng)該是有一個(gè)優(yōu)化的地方,設(shè)一個(gè)標(biāo)識(shí)符標(biāo)識(shí)已經(jīng)加載圖片的index,當(dāng)滾動(dòng)條滾動(dòng)時(shí)就不需要遍歷所有的圖片,只需要遍歷未加載的圖片即可。

          函數(shù)節(jié)流

          在類(lèi)似于滾動(dòng)條滾動(dòng)等頻繁的DOM操作時(shí),總會(huì)提到“函數(shù)節(jié)流、函數(shù)去抖”。

          所謂的函數(shù)節(jié)流,也就是讓一個(gè)函數(shù)不要執(zhí)行的太頻繁,減少一些過(guò)快的調(diào)用來(lái)節(jié)流。

          基本步驟:

          1. 獲取第一次觸發(fā)事件的時(shí)間戳
          2. 獲取第二次觸發(fā)事件的時(shí)間戳
          3. 時(shí)間差如果大于某個(gè)閾值就執(zhí)行事件,然后重置第一個(gè)時(shí)間
          function throttle(fn, mustRun=500) {
           const timer=null;
           let previous=null;
           return function() {
             const now=new Date();
             const context=this;
             const args=arguments;
             if (!previous){
               previous=now;
             }
             const remaining=now - previous;
             if (mustRun && remaining >=mustRun) {
               fn.apply(context, args);
               previous=now;
             }
           }
          }

          這里的 mustRun就是調(diào)用函數(shù)的時(shí)間間隔,無(wú)論多么頻繁的調(diào)用 fn,只有 remaining>=mustRun時(shí) fn才能被執(zhí)行。

          實(shí)驗(yàn)


          頁(yè)面打開(kāi)時(shí)

          可以看出此時(shí)僅僅是加載了img1和img2,其它的img都沒(méi)發(fā)送請(qǐng)求,看看此時(shí)的瀏覽器

          第一張圖片是完整的呈現(xiàn)了,第二張圖片剛進(jìn)入可視區(qū)域,后面的就看不到了~

          頁(yè)面滾動(dòng)時(shí)

          當(dāng)我向下滾動(dòng),此時(shí)瀏覽器是這樣

          此時(shí)第二張圖片完全顯示了,而第三張圖片顯示了一點(diǎn)點(diǎn),這時(shí)候我們看看請(qǐng)求情況

          img3的請(qǐng)求發(fā)出來(lái),而后面的請(qǐng)求還是沒(méi)發(fā)出~

          全部載入時(shí)

          當(dāng)滾動(dòng)條滾到最底下時(shí),全部請(qǐng)求都應(yīng)該是發(fā)出的,如圖

          更新


          方法三 IntersectionObserver

          經(jīng)大佬提醒,發(fā)現(xiàn)了這個(gè)方法

          先附上鏈接:

          jjc大大:

          https://github.com/justjavac/the-front-end-knowledge-you-may-dont-know/issues/10

          阮一峰大大:

          http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html

          API Sketch for Intersection Observers:

          https://github.com/WICG/IntersectionObserver

          IntersectionObserver可以自動(dòng)觀察元素是否在視口內(nèi)。

          var io=new IntersectionObserver(callback, option);
          // 開(kāi)始觀察
          io.observe(document.getElementById('example'));
          // 停止觀察
          io.unobserve(element);
          // 關(guān)閉觀察器
          io.disconnect();

          callback的參數(shù)是一個(gè)數(shù)組,每個(gè)數(shù)組都是一個(gè) IntersectionObserverEntry對(duì)象,包括以下屬性:

          屬性描述time可見(jiàn)性發(fā)生變化的時(shí)間,單位為毫秒rootBounds與getBoundingClientRect()方法的返回值一樣boundingClientRect目標(biāo)元素的矩形區(qū)域的信息intersectionRect目標(biāo)元素與視口(或根元素)的交叉區(qū)域的信息intersectionRatio目標(biāo)元素的可見(jiàn)比例,即intersectionRect占boundingClientRect的比例,完全可見(jiàn)時(shí)為1,完全不可見(jiàn)時(shí)小于等于0target被觀察的目標(biāo)元素,是一個(gè) DOM 節(jié)點(diǎn)對(duì)象

          我們需要用到 intersectionRatio來(lái)判斷是否在可視區(qū)域內(nèi),當(dāng) intersectionRatio>0&&intersectionRatio<=1即在可視區(qū)域內(nèi)。

          代碼

          function checkImgs() {
           const imgs=Array.from(document.querySelectorAll(".my-photo"));
           imgs.forEach(item=> io.observe(item));
          }
          
          function loadImg(el) {
           if (!el.src) {
             const source=el.dataset.src;
             el.src=source;
           }
          }
          
          const io=new IntersectionObserver(ioes=> {
           ioes.forEach(ioe=> {
             const el=ioe.target;
             const intersectionRatio=ioe.intersectionRatio;
             if (intersectionRatio > 0 && intersectionRatio <=1) {
               loadImg(el);
             }
             el.onload=el.onerror=()=> io.unobserve(el);
           });
          });

          源自:segmentfault

          聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請(qǐng)聯(lián)系小編刪除。

          接:https://juejin.im/book/5b936540f265da0a9624b04b/section/5bb6218ee51d450e7762f873

          Lazy-Load,翻譯過(guò)來(lái)是“懶加載”。它是針對(duì)圖片加載時(shí)機(jī)的優(yōu)化:在一些圖片量比較大的網(wǎng)站(比如電商網(wǎng)站首頁(yè),或者團(tuán)購(gòu)網(wǎng)站、小游戲首頁(yè)等),如果我們嘗試在用戶(hù)打開(kāi)頁(yè)面的時(shí)候,就把所有的圖片資源加載完畢,那么很可能會(huì)造成白屏、卡頓等現(xiàn)象,因?yàn)閳D片真的太多了,一口氣處理這么多任務(wù),瀏覽器做不到啊!

          但我們?cè)傧耄脩?hù)真的需要這么多圖片嗎?不對(duì),用戶(hù)點(diǎn)開(kāi)頁(yè)面的瞬間,呈現(xiàn)給他的只有屏幕的一部分(我們稱(chēng)之為首屏)。只要我們可以在頁(yè)面打開(kāi)的時(shí)候把首屏的圖片資源加載出來(lái),用戶(hù)就會(huì)認(rèn)為頁(yè)面是沒(méi)問(wèn)題的。至于下面的圖片,我們完全可以等用戶(hù)下拉的瞬間再即時(shí)去請(qǐng)求、即時(shí)呈現(xiàn)給他。這樣一來(lái),性能的壓力小了,用戶(hù)的體驗(yàn)卻沒(méi)有變差——這個(gè)延遲加載的過(guò)程,就是 Lazy-Load。

          現(xiàn)在我們打開(kāi)掘金首頁(yè):

          右側(cè)可能會(huì)出現(xiàn)的圖片,即下圖示例:

          大家現(xiàn)在以盡可能快的速度,瘋狂向下拉動(dòng)頁(yè)面


          主站蜘蛛池模板: 无码人妻一区二区三区免费视频| 国产精品亚洲专区一区| 亚洲一区二区三区无码中文字幕| 日韩精品无码一区二区三区AV| 综合久久一区二区三区| 久久亚洲AV午夜福利精品一区| 亚洲av成人一区二区三区| 精品一区二区三区影院在线午夜 | 99精品国产一区二区三区不卡| 福利电影一区二区| 3D动漫精品一区二区三区| 内射女校花一区二区三区| 国产成人一区二区三区精品久久 | 久久无码人妻精品一区二区三区| 亚洲欧美日韩中文字幕一区二区三区 | 国产精品熟女一区二区| 精彩视频一区二区三区| 精品熟人妻一区二区三区四区不卡| 国产福利一区二区在线视频| 国产精品无码亚洲一区二区三区| 久久综合九九亚洲一区| 国产精品小黄鸭一区二区三区 | 精品人妻无码一区二区三区蜜桃一| 日韩一区二区久久久久久| 久久国产精品一区| 无码精品前田一区二区| 爱爱帝国亚洲一区二区三区| 精品无人区一区二区三区在线 | 韩国福利一区二区三区高清视频 | 国产精品美女一区二区视频 | 在线免费观看一区二区三区| 亚洲综合色自拍一区| 国产精品综合一区二区| 色窝窝无码一区二区三区成人网站| 精品一区二区三区影院在线午夜| 国产成人精品久久一区二区三区| 精品一区二区三区免费视频| 精品国产精品久久一区免费式| 亚洲av午夜福利精品一区| 一区视频免费观看| 日韩美一区二区三区|