整合營銷服務(wù)商

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

          免費咨詢熱線:

          3種Javascript圖片預(yù)加載的方法詳解

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

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

          方法一:用css和JavaScript實現(xiàn)預(yù)加載

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

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

          #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選擇器應(yīng)用到(X)html元素中,我們便可通過CSS的background屬性將圖片預(yù)加載到屏幕外的背景上。

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

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

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

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

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

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

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

          方法二:僅使用JavaScript實現(xiàn)預(yù)加載

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

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

          JavaScript代碼段1

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

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

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

          JavaScript代碼段2

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

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

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

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

          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實現(xiàn)預(yù)加載

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

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

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

          下面,我們看看如何用JavaScript來實現(xiàn)該加載過程:

          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創(chuàng)建三個元素來實現(xiàn)三個文件的預(yù)加載。正如上面提到的那樣,使用Ajax,加載文件不會應(yīng)用到加載頁面上。從這點上看,Ajax方法優(yōu)越于JavaScript。


          - End -

          tml2canvas

          簡介

          我們可以直接在瀏覽器端使用html2canvas,對整個或局部頁面進行‘截圖’。但這并不是真的截圖,而是通過遍歷頁面DOM結(jié)構(gòu),收集所有元素信息及相應(yīng)樣式,渲染出canvas image。

          由于html2canvas只能將它能處理的生成canvas image,因此渲染出來的結(jié)果并不是100%與原來一致。但它不需要服務(wù)器參與,整個圖片都由客戶端瀏覽器生成,使用很方便。

          使用

          使用的API也很簡潔,下面代碼可以將某個元素渲染成canvas:

          html2canvas(element, {
           onrendered: function(canvas) {
           // canvas is the final rendered <canvas> element
           }
          });
          

          通過onrendered方法,可以將生成的canvas進行回調(diào),比如插入到頁面中:

          html2canvas(element, {
           onrendered: function(canvas) {
           document.body.appendChild(canvas);
           }
          });
          

          做個小例子代碼如下,在線展示鏈接demo1

          <html>
           <head>
           <title>html2canvas example</title>
           <style type="text/css">...</style>
           </head>
           <body>
           <header>
           <nav>
           <ul>
           <li>one</li>
           ...
           </ul>
           </nav>
           </header>
           <section>
           <aside>
           <h3>it is a title</h3>
           <a href="">Stone Giant</a>
           ...
           </aside>
           <article>
           <img src="./Stone.png">
           <h2>Stone Giant</h2>
           <p>Coming ... </p>
           <p>以一團石頭...</p>
           </article>
           </section>
           <footer>write by linwalker @2017</footer>
           <script type="text/javascript" src="./html2canvas.js"></script>
           <script type="text/javascript">
           html2canvas(document.body, {
           onrendered:function(canvas) {
           document.body.appendChild(canvas)
           }
           })
           </script>
           </body>
          </html>
          

          這個例子將頁面body中的元素渲染成canvas,并插入到body中

          jsPDF

          jsPDF庫可以用于瀏覽器端生成PDF。

          文字生成PDF

          使用方法如下:

          // 默認a4大小,豎直方向,mm單位的PDF
          var doc = new jsPDF();
          // 添加文本‘Download PDF’
          doc.text('Download PDF!', 10, 10);
          doc.save('a4.pdf');
          

          在線演示demo2

          圖片生成PDF

          使用方法如下:

          // 三個參數(shù),第一個方向,第二個單位,第三個尺寸格式
          var doc = new jsPDF('landscape','pt',[205, 115])
          // 將圖片轉(zhuǎn)化為dataUrl
          var imageData = ‘data:image/png;base64,iVBORw0KGgo...’;
          doc.addImage(imageData, 'PNG', 0, 0, 205, 115);
          doc.save('a4.pdf');
          

          在線演示demo3

          文字與圖片生成PDF

          // 三個參數(shù),第一個方向,第二個尺寸,第三個尺寸格式
          var doc = new jsPDF('landscape','pt',[205, 155])
          // 將圖片轉(zhuǎn)化為dataUrl
          var imageData = ‘data:image/png;base64,iVBORw0KGgo...’;
          //設(shè)置字體大小
          doc.setFontSize(20);
          //10,20這兩參數(shù)控制文字距離左邊,與上邊的距離
          doc.text('Stone', 10, 20);
          // 0, 40, 控制文字距離左邊,與上邊的距離
          doc.addImage(imageData, 'PNG', 0, 40, 205, 115);
          doc.save('a4.pdf')
          

          在線演示demo4

          生成pdf需要把轉(zhuǎn)化的元素添加到j(luò)sPDF實例中,也有添加html的功能,但某些元素?zé)o法生成在pdf中,因此可以使用html2canvas + jsPDF的方式將頁面轉(zhuǎn)成pdf。通過html2canvas將遍歷頁面元素,并渲染生成canvas,然后將canvas圖片格式添加到j(luò)sPDF實例,生成pdf。

          html2canvas + jsPDF

          單頁

          將demo1的例子修改下:

          <script type="text/javascript" src="./js/jsPdf.debug.js"></script>
          <script type="text/javascript">
           var downPdf = document.getElementById("renderPdf");
           downPdf.onclick = function() {
           html2canvas(document.body, {
           onrendered:function(canvas) {
           //返回圖片dataURL,參數(shù):圖片格式和清晰度(0-1)
           var pageData = canvas.toDataURL('image/jpeg', 1.0);
           //方向默認豎直,尺寸ponits,格式a4[595.28,841.89]
           var pdf = new jsPDF('', 'pt', 'a4');
           //addImage后兩個參數(shù)控制添加圖片的尺寸,此處將頁面高度按照a4紙寬高比列進行壓縮
           pdf.addImage(pageData, 'JPEG', 0, 0, 595.28, 592.28/canvas.width * canvas.height );
           pdf.save('stone.pdf');
           }
           })
           }
          </script>
          

          在線演示demo5

          如果頁面內(nèi)容根據(jù)a4比例轉(zhuǎn)化后高度超過a4紙高度呢,生成的pdf會怎么樣?會分頁嗎?

          你可以試試,驗證一下自己的想法: demo6

          jsPDF提供了一個很有用的API,addPage(),我們可以通過pdf.addPage(),來添加一頁pdf,然后通過pdf.addImage(...),將圖片賦予這頁pdf來顯示。

          那么我們?nèi)绾未_定哪里分頁?

          這個問題好回答,我們可以設(shè)置一個pageHeight,超過這個高度的內(nèi)容放入下一頁pdf。

          來捋一下思路,將html頁面內(nèi)容生成canvas圖片,通過addImage將第一頁圖片添加到pdf中,超過一頁內(nèi)容,通過addPage()添加pdf頁數(shù),然后再通過addImage將下一頁圖片添加到pdf中。

          嗯~,很好!巴特,難道沒有發(fā)現(xiàn)問題嗎?

          這個方法實現(xiàn)的前提是 — — 我們能根據(jù)pageHeight先將整頁內(nèi)容生成的canvas圖片分割成對應(yīng)的小圖片,然后一個蘿卜一個坑,一頁一頁addImage進去。

          What? 想一想我們的canvas是腫么來的,不用拉上去,直接看下面:

          html2canvas(document.body, {
           onrendered:function(canvas) {
           //it is here we handle the canvas
           }
          })
          

          這里的body就是要生成canvas的元素對象,一個元素生成一個canvas;那么我們需要一頁一頁的canvas,也就是說。。。

          你覺得可能嗎? 我覺得不太現(xiàn)實,按這思路要獲取頁面上不同位置的DOM元素,然后通過htnl2canvas(element,option)來處理,先不說能不能剛好在每個pageHeight的位置剛好找到一個DOM元素,就算找到了,這樣做累不累。

          累的話

          :)可以看看下面這種方法

          多頁

          我提供的思路是我們只生成一個canvas,對就一個,轉(zhuǎn)化元素就是你要轉(zhuǎn)成pdf內(nèi)容的母元素,在這篇demo里就是body了;其他不變,也是超過一頁內(nèi)容就addPage,然后addImage,只不過這里添加的是同一個canvas。

          當(dāng)然這樣做只會出現(xiàn)多頁重復(fù)的pdf,那到底怎么實現(xiàn)正確分頁顯示。其實主要利用了jsPDF的兩點:

          - 超過jsPDF實例格式尺寸的內(nèi)容不顯示
          (var pdf = new jsPDF('', 'pt', 'a4'); demo中就是a4紙的尺寸)
          - addImage有兩個參數(shù)可以控制圖片在pdf中的位置
          

          雖然每一頁pdf上顯示的圖片是相同的,但我們通過調(diào)整圖片的位置,產(chǎn)生了分頁的錯覺。以第二頁為例,將豎直方向上的偏移設(shè)置為-841.89即一張a4紙的高度,又因為超過a4紙高度范圍的圖片不顯示,所以第二頁顯示了圖片豎直方向上[841.89,1682.78]范圍內(nèi)的內(nèi)容,這就得到了分頁的效果,以此類推。

          還是看代碼吧:

          html2canvas(document.body, {
           onrendered:function(canvas) {
           var contentWidth = canvas.width;
           var contentHeight = canvas.height;
           //一頁pdf顯示html頁面生成的canvas高度;
           var pageHeight = contentWidth / 592.28 * 841.89;
           //未生成pdf的html頁面高度
           var leftHeight = contentHeight;
           //頁面偏移
           var position = 0;
           //a4紙的尺寸[595.28,841.89],html頁面生成的canvas在pdf中圖片的寬高
           var imgWidth = 595.28;
           var imgHeight = 592.28/contentWidth * contentHeight;
           var pageData = canvas.toDataURL('image/jpeg', 1.0);
           var pdf = new jsPDF('', 'pt', 'a4');
           //有兩個高度需要區(qū)分,一個是html頁面的實際高度,和生成pdf的頁面高度(841.89)
           //當(dāng)內(nèi)容未超過pdf一頁顯示的范圍,無需分頁
           if (leftHeight < pageHeight) {
           pdf.addImage(pageData, 'JPEG', 0, 0, imgWidth, imgHeight );
           } else {
           while(leftHeight > 0) {
           pdf.addImage(pageData, 'JPEG', 0, position, imgWidth, imgHeight)
           leftHeight -= pageHeight;
           position -= 841.89;
           //避免添加空白頁
           if(leftHeight > 0) {
           pdf.addPage();
           }
           }
           }
           pdf.save('content.pdf');
           }
          })
          

          在線演示demo7

          兩邊留邊距

          修改imgWidth,并且在addImage時x方向參數(shù)設(shè)置你要的邊距,具體代碼如下

          var imgWidth = 555.28;
          var imgHeight = 555.28/contentWidth * contentHeight;
          ...
          pdf.addImage(pageData, 'JPEG', 20, 0, imgWidth, imgHeight );
          ...
          pdf.addImage(pageData, 'JPEG', 20, position, imgWidth, imgHeight);
          

          在線演示demo8

          :如何用 JS 一次獲取 HTML 表單的所有字段 ?

          考慮一個簡單的 HTML 表單,用于將任務(wù)保存在待辦事項列表中:

            <form>
              <label for="name">用戶名</label>
              <input type="text" id="name" name="name" required>
          
              <label for="description">簡介</label>
              <input type="text" id="description" name="description" required>
          
              <label for="task">任務(wù)</label>
              <textarea id="task" name="task" required></textarea>
          
              <button type="submit">提交</button>
            </form>
          

          上面每個字段都有對應(yīng)的的type,ID和 name屬性,以及相關(guān)聯(lián)的label。用戶單擊“提交”按鈕后,我們?nèi)绾螐拇吮韱沃蝎@取所有數(shù)據(jù)?

          有兩種方法:一種是用黑科技,另一種是更清潔,也是最常用的方法。為了演示這種方法,我們先創(chuàng)建form.js,并引入文件中。

          從事件 target 獲取表單字段

          首先,我們在表單上為Submit事件注冊一個事件偵聽器,以停止默認行為(它們將數(shù)據(jù)發(fā)送到后端)。

          然后,使用this.elements或event.target.elements訪問表單字段:

          相反,如果需要響應(yīng)某些用戶交互而動態(tài)添加更多字段,那么我們需要使用FormData。

          使用 FormData

          首先,我們在表單上為submit事件注冊一個事件偵聽器,以停止默認行為。接著,我們從表單構(gòu)建一個FormData對象:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
          });
          

          除了append()、delete()、get()、set()之外,F(xiàn)ormData 還實現(xiàn)了Symbol.iterator。這意味著它可以用for...of 遍歷:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
          
            for (const formElement of formData) {
              console.log(formElement);
            }
          })
          

          除了上述方法之外,entries()方法獲取表單對象形式:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
            const entries = formData.entries();
            const data = Object.fromEntries(entries);
          });
          

          這也適合Object.fromEntries() (ECMAScript 2019)

          為什么這有用?如下所示:

          const form = document.forms[0];
          
          form.addEventListener("submit", function(event) {
            event.preventDefault();
            const formData = new FormData(this);
            const entries = formData.entries();
            const data = Object.fromEntries(entries);
          
            // send out to a REST API
            fetch("https://some.endpoint.dev", {
              method: "POST",
              body: JSON.stringify(data),
              headers: {
                "Content-Type": "application/json"
              }
            })
              .then(/**/)
              .catch(/**/);
          });
          

          一旦有了對象,就可以使用fetch發(fā)送有效負載。

          小心:如果在表單字段上省略name屬性,那么在FormData對象中剛沒有生成。

          總結(jié)

          要從HTML表單中獲取所有字段,可以使用:

          • this.elements或event.target.elements,只有在預(yù)先知道所有字段并且它們保持穩(wěn)定的情況下,才能使用。

          使用FormData構(gòu)建具有所有字段的對象,之后可以轉(zhuǎn)換,更新或?qū)⑵浒l(fā)送到遠程API。*


          作者:VALENTINO GAGLIARDI 譯者:前端小智 來源:valentinog

          原文:https://www.valentinog.com/blog/form-data/


          主站蜘蛛池模板: 国产日韩精品一区二区在线观看播放 | 一区二区三区日本电影| 国产伦理一区二区三区| 激情内射日本一区二区三区| 国产精品视频无圣光一区| 少妇激情av一区二区| 狠狠做深爱婷婷综合一区| 精品国产一区二区三区免费看| 无码国产精品一区二区免费式芒果 | 伦精品一区二区三区视频| 性色AV一区二区三区| 精品aⅴ一区二区三区| 好吊视频一区二区三区| chinese国产一区二区| 国产一区在线电影| 冲田杏梨AV一区二区三区| 3d动漫精品成人一区二区三| 亚洲一区二区电影| 久久久久99人妻一区二区三区| 国产精品 视频一区 二区三区| 日韩十八禁一区二区久久| 国产成人久久一区二区三区| 日本韩国一区二区三区| 国产在线步兵一区二区三区| 国产在线步兵一区二区三区| 精品91一区二区三区| 日本一区二区在线不卡| 无码人妻久久一区二区三区蜜桃| 日本一道一区二区免费看| 日本精品啪啪一区二区三区| 立川理惠在线播放一区| 国产A∨国片精品一区二区| 一区二区三区免费精品视频| 久久精品无码一区二区app| 波多野结衣AV无码久久一区| 性色A码一区二区三区天美传媒| 激情亚洲一区国产精品| 亚洲国产高清在线精品一区| 亚洲国产欧美日韩精品一区二区三区| 中文字幕精品一区二区| 国产一区在线视频观看|