整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          3種Javascript圖片預加載的方法詳解

          3種Javascript圖片預加載的方法詳解

          加載圖片是提高用戶體驗的一個很好方法。圖片預先加載到瀏覽器中,訪問者便可順利地在你的網站上沖浪,并享受到極快的加載速度。

          這對圖片畫廊及圖片占據很大比例的網站來說十分有利,它保證了圖片快速、無縫地發布,也可幫助用戶在瀏覽你網站內容時獲得更好的用戶體驗。本文將分享三個不同的預加載技術,來增強網站的性能與可用性。

          方法一:用css和JavaScript實現預加載

          實現預加載圖片有很多方法,包括使用css、JavaScript及兩者的各種組合。這些技術可根據不同設計場景設計出相應的解決方案,十分高效。

          單純使用CSS,可容易、高效地預加載圖片,代碼如下:

          #preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }  
          #preload-02 { background: url(http://domain.tld/image-02.png) no-repeat -9999px -9999px; }  
          #preload-03 { background: url(http://domain.tld/image-03.png) no-repeat -9999px -9999px; }

          將這三個ID選擇器應用到(X)html元素中,我們便可通過CSS的background屬性將圖片預加載到屏幕外的背景上。

          只要這些圖片的路徑保持不變,當它們在Web頁面的其他地方被調用時,瀏覽器就會在渲染過程中使用預加載(緩存)的圖片。簡單、高效,不需要任何JavaScript。

          該方法雖然高效,但仍有改進余地。使用該法加載的圖片會同頁面的其他內容一起加載,增加了頁面的整體加載時間。

          為了解決這個問題,我們增加了一些JavaScript代碼,來推遲預加載的時間,直到頁面加載完畢。代碼如下:

          function preloader() {  
              if (document.getElementById) {  
                  document.getElementById("preload-01").style.background="url(http://domain.tld/image-01.png) no-repeat -9999px -9999px";  
                  document.getElementById("preload-02").style.background="url(http://domain.tld/image-02.png) no-repeat -9999px -9999px";  
                  document.getElementById("preload-03").style.background="url(http://domain.tld/image-03.png) no-repeat -9999px -9999px";  
              }  
          }  
          function addLoadEvent(func) {  
              var oldonload=window.onload;  
              if (typeof window.onload !='function') {  
                  window.onload=func;  
              } else {  
                  window.onload=function() {  
                      if (oldonload) {  
                          oldonload();  
                      }  
                      func();  
                  }  
              }  
          }  
          addLoadEvent(preloader);
          

          在該腳本的第一部分,我們獲取使用類選擇器的元素,并為其設置了background屬性,以預加載不同的圖片。

          該腳本的第二部分,我們使用addLoadEvent()函數來延遲preloader()函數的加載時間,直到頁面加載完畢。

          如果JavaScript無法在用戶的瀏覽器中正常運行,會發生什么?很簡單,圖片不會被預加載,當頁面調用圖片時,正常顯示即可。

          方法二:僅使用JavaScript實現預加載

          上述方法有時確實很高效,但我們逐漸發現它在實際實現過程中會耗費太多時間。相反,我更喜歡使用純JavaScript來實現圖片的預加載。

          下面將提供兩種這樣的預加載方法,它們可以很漂亮地工作于所有現代瀏覽器之上。

          JavaScript代碼段1

          只需簡單編輯、加載所需要圖片的路徑與名稱即可,很容易實現:

          <div class="hidden">  
              <script type="text/javascript">  
                     var images=new Array()  
                      function preload() {  
                          for (i=0; i < preload.arguments.length; i++) {  
                              images[i]=new Image()  
                              images[i].src=preload.arguments[i]  
                          }  
                      }  
                      preload(  
                          "http://domain.tld/gallery/image-001.jpg",  
                          "http://domain.tld/gallery/image-002.jpg",  
                          "http://domain.tld/gallery/image-003.jpg"  
                      )  
          </script> 
          </div>
          

          該方法尤其適用預加載大量的圖片。我的畫廊網站使用該技術,預加載圖片數量達50多張。將該腳本應用到登錄頁面,只要用戶輸入登錄帳號,大部分畫廊圖片將被預加載。

          JavaScript代碼段2

          該方法與上面的方法類似,也可以預加載任意數量的圖片。將下面的腳本添加入任何Web頁中,根據程序指令進行編輯即可。

          <div class="hidden">  
              <script type="text/javascript">  
                      if (document.images) {  
                          img1=new Image();  
                          img2=new Image();  
                          img3=new Image();  
                          img1.src="http://domain.tld/path/to/image-001.gif";  
                          img2.src="http://domain.tld/path/to/image-002.gif";  
                          img3.src="http://domain.tld/path/to/image-003.gif";  
                      }    
          </script>  
          </div>
          

          正如所看見,每加載一個圖片都需要創建一個變量,如“img1=new Image();”,及圖片源地址聲明,如“img3.src=“../path/to/image-003.gif”;”。參考該模式,你可根據需要加載任意多的圖片。

          我們又對該方法進行了改進。將該腳本封裝入一個函數中,并使用 addLoadEvent(),延遲預加載時間,直到頁面加載完畢。

          function preloader() {  
              if (document.images) {  
                  var img1=new Image();  
                  var img2=new Image();  
                  var img3=new Image();  
                  img1.src="http://domain.tld/path/to/image-001.gif";  
                  img2.src="http://domain.tld/path/to/image-002.gif";  
                  img3.src="http://domain.tld/path/to/image-003.gif";  
              }  
          }  
          function addLoadEvent(func) {  
              var oldonload=window.onload;  
              if (typeof window.onload !='function') {  
                  window.onload=func;  
              } else {  
                  window.onload=function() {  
                      if (oldonload) {  
                          oldonload();  
                      }  
                      func();  
                  }  
              }  
          }  
          addLoadEvent(preloader);
          

          方法三:使用Ajax實現預加載

          上面所給出的方法似乎不夠酷,那現在來看一個使用Ajax實現圖片預加載的方法。該方法利用DOM,不僅僅預加載圖片,還會預加載CSS、JavaScript等相關的東西。使用Ajax,比直接使用JavaScript,優越之處在于JavaScript和CSS的加載不會影響到當前頁面。該方法簡潔、高效。

          window.onload=function() {  
              setTimeout(function() {  
                  // XHR to request a js and a CSS  
                  var xhr=new XMLHttpRequest();  
                  xhr.open('GET', 'http://domain.tld/preload.js');  
                  xhr.send('');  
                  xhr=new XMLHttpRequest();  
                  xhr.open('GET', 'http://domain.tld/preload.css');  
                  xhr.send('');  
                  // preload image  
                  new Image().src="http://domain.tld/preload.png";  
              }, 1000);  
          };
          

          上面代碼預加載了“preload.js”、“preload.css”和“preload.png”。1000毫秒的超時是為了防止腳本掛起,而導致正常頁面出現功能問題。

          下面,我們看看如何用JavaScript來實現該加載過程:

          window.onload=function() {  
              setTimeout(function() {  
                  // reference to <head>  
                  var head=document.getElementsByTagName('head')[0];  
                  // a new CSS  
                  var css=document.createElement('link');  
                  css.type="text/css";  
                  css.rel="stylesheet";  
                  css.href="http://domain.tld/preload.css";  
                  // a new JS  
                  var js=document.createElement("script");  
                  js.type="text/javascript";  
                  js.src="http://domain.tld/preload.js";  
                  // preload JS and CSS  
                  head.appendChild(css);  
                  head.appendChild(js);  
                  // preload image  
                  new Image().src="http://domain.tld/preload.png";  
              }, 1000); 
          };
          

          這里,我們通過DOM創建三個元素來實現三個文件的預加載。正如上面提到的那樣,使用Ajax,加載文件不會應用到加載頁面上。從這點上看,Ajax方法優越于JavaScript。


          - End -


          加載


          什么是懶加載

          懶加載其實就是延遲加載,是一種對網頁性能優化可方式,比如當訪問一個頁面的時候,優先顯示可視區域的圖片而不一次性加載所有圖片,當需要顯示的時候再發送圖片請求,避免打開網頁時加載過多資源。

          什么時候用懶加載

          當頁面中需要一次性載入很多圖片的時候,往往都是需要用懶加載的。

          懶加載原理

          我們都知道HTML中的 <img>標簽是代表文檔中的一個圖像。。說了個廢話。。

          <img>標簽有一個屬性是 src,用來表示圖像的URL,當這個屬性的值不為空時,瀏覽器就會根據這個值發送請求。如果沒有 src屬性,就不會發送請求。

          嗯?貌似這點可以利用一下?

          我先不設置 src,需要的時候再設置?

          nice,就是這樣。

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

          實現


          HTML結構

          <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>

          仔細觀察一下, <img>標簽此時是沒有 src屬性的,只有 alt和 data-src屬性。

          alt 屬性是一個必需的屬性,它規定在圖像無法顯示時的替代文本。 data-* 全局屬性:構成一類名稱為自定義數據屬性的屬性,可以通過 HTMLElement.dataset來訪問。

          如何判斷元素是否在可視區域

          方法一

          網上看到好多這種方法,稍微記錄一下。

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

          然后判斷②-③<①是否成立,如果成立,元素就在可視區域內。

          方法二(推薦)

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

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

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

          MDN上有這樣一張圖:

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

          我們思考一下,什么情況下圖片進入可視區域。

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

          隨著滾動條的向下滾動, bound.top會越來越小,也就是圖片到可視區域頂部的距離越來越小,當 bound.top===clientHeight時,圖片的上沿應該是位于可視區域下沿的位置的臨界點,再滾動一點點,圖片就會進入可視區域。

          也就是說,在 bound.top<=clientHeight時,圖片是在可視區域內的。

          我們這樣判斷:

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

          這里有個+100是為了提前加載。

          加載圖片

          頁面打開時需要對所有圖片進行檢查,是否在可視區域內,如果是就加載。

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

          這里應該是有一個優化的地方,設一個標識符標識已經加載圖片的index,當滾動條滾動時就不需要遍歷所有的圖片,只需要遍歷未加載的圖片即可。

          函數節流

          在類似于滾動條滾動等頻繁的DOM操作時,總會提到“函數節流、函數去抖”。

          所謂的函數節流,也就是讓一個函數不要執行的太頻繁,減少一些過快的調用來節流。

          基本步驟:

          1. 獲取第一次觸發事件的時間戳
          2. 獲取第二次觸發事件的時間戳
          3. 時間差如果大于某個閾值就執行事件,然后重置第一個時間
          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就是調用函數的時間間隔,無論多么頻繁的調用 fn,只有 remaining>=mustRun時 fn才能被執行。

          實驗


          頁面打開時

          可以看出此時僅僅是加載了img1和img2,其它的img都沒發送請求,看看此時的瀏覽器

          第一張圖片是完整的呈現了,第二張圖片剛進入可視區域,后面的就看不到了~

          頁面滾動時

          當我向下滾動,此時瀏覽器是這樣

          此時第二張圖片完全顯示了,而第三張圖片顯示了一點點,這時候我們看看請求情況

          img3的請求發出來,而后面的請求還是沒發出~

          全部載入時

          當滾動條滾到最底下時,全部請求都應該是發出的,如圖

          更新


          方法三 IntersectionObserver

          經大佬提醒,發現了這個方法

          先附上鏈接:

          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可以自動觀察元素是否在視口內。

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

          callback的參數是一個數組,每個數組都是一個 IntersectionObserverEntry對象,包括以下屬性:

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

          我們需要用到 intersectionRatio來判斷是否在可視區域內,當 intersectionRatio>0&&intersectionRatio<=1即在可視區域內。

          代碼

          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

          聲明:文章著作權歸作者所有,如有侵權,請聯系小編刪除。

          JavaScript中,您可以使用HTML5的<input type="file">元素來實現圖片上傳功能。

          以下是一個簡單的示例代碼,演示如何在JavaScript中上傳圖片:

          HTML部分:

          <input type="file" id="uploadInput">
          <button onclick="uploadImage()">上傳圖片</button>
          

          JavaScript部分:

          function uploadImage() {
            var fileInput=document.getElementById('uploadInput');
            var file=fileInput.files[0];
          
            if (file) {
              var formData=new FormData();
              formData.append('image', file);
          
              // 發送圖片數據到服務器
              // 這里可以使用XMLHttpRequest或fetch等方法發送請求
              // 請根據您的需求選擇適當的方法
              // 示例中使用XMLHttpRequest發送POST請求
              var xhr=new XMLHttpRequest();
              xhr.open('POST', '/upload', true);
              xhr.onload=function() {
                if (xhr.status===200) {
                  // 上傳成功
                  console.log('圖片上傳成功');
                } else {
                  // 上傳失敗
                  console.log('圖片上傳失敗');
                }
              };
              xhr.send(formData);
            }
          }
          

          API部分:

          [HttpPost]
          [RequestSizeLimit(5242880)]
           public async Task<APIResult> upload(IFormCollection collection)
           {
          
                      APIResult rtn=new APIResult();
          
                      if (collection==null)
                      {
                          rtn.code=-100;
                          rtn.msg="圖片列表為空";
                          return rtn;
                      }
                      else
                      {
                          try
                          {
                              string file_path="";
                              // 預處理 用戶參數:用戶指定子路徑                   
                              string userPath=DateTime.Now.ToString("yyyy-MM-dd");
                              if (collection.ContainsKey("path"))
                              {
                                  collection.TryGetValue("path", out Microsoft.Extensions.Primitives.StringValues val);
                                  if (!val.Equals("undefined"))
                                  {
                                      userPath=val.ToString();
                                  }
                              }
          
                              // 預處理 文件路徑
                              // 注意:這里可能會根據不同的環境來 修改 路徑前面是否需要添加 /
                              // 當發現上傳不成功,目錄無法創建時,可以嘗試修改這里
                              file_path=$"upload/imgs/{userPath}/";
                              var uploadPath=Path.Combine(_webHostEnvironment.WebRootPath, file_path);
                              if (!Directory.Exists(uploadPath))
                              {
                                  Directory.CreateDirectory(uploadPath);
                              }
          
                              // 處理文件
                              FormFileCollection filelist=(FormFileCollection)collection.Files;
                              foreach (IFormFile file in filelist)
                              {
                                  // 保存文件到磁盤
                                  string name=file.FileName;
                                  string FilePath=Path.Combine(uploadPath, name);
                                  string type=Path.GetExtension(name);
                                  using (var stream=System.IO.File.Create(FilePath))
                                  {
                                      await file.CopyToAsync(stream);
                                  };
          
                                  // 保存文件信息到表
                                  Sys_File f=new Sys_File();
                                  f.code="image";
                                  f.name=name;
                                  f.file_type=type.Trim('.');
                                  f.file_group=userPath;
                                  f.file_path=$"/{file_path}{name}";
                                  f.is_active=true;
                                  f.memo="";
                                  f.createTime=DateTime.Now;
                                  using (var dbctx=DBHelper.db)
                                  {
                                      await dbctx.AddAsync(f);
                                      await dbctx.SaveChangesAsync();
                                  };
                                  // 返回消息,包含文件路徑
                                  rtn.datas=$"/{file_path}{name}";
                                  rtn.code=100;
                                  rtn.msg="文件已保存!";
                              }
                          }
                          catch (Exception ex)
                          {
                              rtn.code=-200;
                              rtn.msg="圖片保存失敗!";
                              Log4NetUnit.Instance.Log.Error("圖片保存失敗:" + ex.Message);
                          }
                          return rtn;
                      }
                  }


          在這個示例中,我們首先在HTML中創建了一個<input type="file">元素,用于選擇要上傳的圖片。

          然后,我們在JavaScript中編寫了一個uploadImage函數,該函數在點擊"上傳圖片"按鈕時觸發。

          uploadImage函數中,我們首先獲取到<input>元素,并從中獲取到用戶選擇的圖片文件。

          然后,我們創建一個FormData對象,并將圖片文件添加到其中。

          接下來,我們可以使用XMLHttpRequest或fetch等方法將圖片數據發送到服務器。

          在示例中,我們使用XMLHttpRequest發送了一個POST請求,將圖片數據作為FormData發送到/upload端點。

          您需要根據您的實際情況修改URL和請求方法。

          當請求完成時,我們可以根據響應的狀態碼來判斷上傳是否成功。

          在示例中,如果狀態碼為200,則表示上傳成功,否則表示上傳失敗。

          請注意,由于安全性限制,JavaScript無法直接訪問用戶的文件系統。

          因此,用戶必須手動選擇要上傳的文件。


          主站蜘蛛池模板: 日韩精品一区二区三区中文| 好湿好大硬得深一点动态图91精品福利一区二区 | 三上悠亚日韩精品一区在线| 久久高清一区二区三区| 色狠狠一区二区三区香蕉| 精品一区精品二区| 人妻av无码一区二区三区| 夜夜爽一区二区三区精品| 亚洲乱色熟女一区二区三区蜜臀 | 高清国产AV一区二区三区| 日本精品啪啪一区二区三区| 无码国产伦一区二区三区视频| 波多野结衣电影区一区二区三区| 人妖在线精品一区二区三区| 麻豆精品久久久一区二区| 国产观看精品一区二区三区| 国内精品一区二区三区最新| 亚洲av成人一区二区三区在线播放| 黑人大战亚洲人精品一区| 日亚毛片免费乱码不卡一区| 亚洲AV成人精品一区二区三区| 精品无码国产一区二区三区AV| 成人国内精品久久久久一区| 无码AV一区二区三区无码| 成人毛片一区二区| 亚洲视频一区在线| 亚洲一区二区久久| 一区二区精品在线| 亚洲AV无码一区二区乱子伦| 成人精品视频一区二区三区| 变态调教一区二区三区| 无码精品人妻一区二区三区影院| 国产一区二区三区播放心情潘金莲 | 中文字幕日韩精品一区二区三区| 一区二区三区福利视频免费观看| 2014AV天堂无码一区| 中文人妻av高清一区二区| 国产亚洲一区二区精品| 日本一区精品久久久久影院| 无码少妇一区二区| 亚欧在线精品免费观看一区|