乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      前端文件上傳基礎(chǔ)

       埃德溫會(huì)館 2017-02-14

      文章來源

      前端文件上傳基礎(chǔ)
      作者:龍運(yùn)霞 2017-01-23 19:49
      本篇文章僅限網(wǎng)易公司內(nèi)部分享,如需轉(zhuǎn)載,請(qǐng)取得作者本人同意授權(quán)

      上傳文件已經(jīng)是個(gè)已經(jīng)成熟的前端技術(shù),目前開源的拿來即用的前端上傳插件也比較多,諸如:Web Uploader、JSAjaxFIleUploaderjQuery-File-Upload,通常這些上傳插件包含的功能有:選擇上傳、支持拖拽、MD5校驗(yàn)、圖片預(yù)覽、上傳進(jìn)度顯示等功能; 這篇文章主要溫習(xí)一下前端上傳控件的功能實(shí)現(xiàn)原理,以及上傳功能如何做到功能的漸進(jìn)式增強(qiáng)。

      文件上傳方式

      文件上傳最原始的方式form元素表單提交,發(fā)展后form原始+iframe實(shí)現(xiàn)異步文件上傳,到后來HTML5出現(xiàn)ajax實(shí)現(xiàn)文件上傳。所以通常上傳控件向下兼容的方案通常是高版本瀏覽器采用ajax方式,低版本瀏覽器采用iframe+form表單形式。

      form表單提交

      <form id="j-puload-form" action="/fileUpload" method="post" enctype="multipart/form-data">    
          <input type="file" id="j-upload-input" name="upload"/><button type="submit">提交</button>
      </form>
      

      form表單屬性中action屬性規(guī)定后端處理文件上傳的路徑;method屬性規(guī)定上傳文件的方法post or get;enctype屬性規(guī)定在發(fā)送到服務(wù)器之前應(yīng)該如何對(duì)表單數(shù)據(jù)進(jìn)行編碼,在使用包含文件上傳控件的表單時(shí)必須使用“multipart/form-data”。 form表單提交

      iframe封裝form表單

      使用form元素比較簡(jiǎn)單,但缺點(diǎn)也比較明顯:上傳同步、上傳完成頁面會(huì)刷新; 在HTML5出現(xiàn)之前,想要實(shí)現(xiàn)文件異步上傳,只能通過iframe+form實(shí)現(xiàn);

      實(shí)現(xiàn)方式

      原理:文件上傳時(shí)在頁面中動(dòng)態(tài)創(chuàng)建一個(gè)iframe元素和一個(gè)form元素,并將form元素的target屬性指向動(dòng)態(tài)創(chuàng)建iframe元素。當(dāng)用戶完成選擇文件動(dòng)作時(shí),提交子頁面中的 form。這時(shí),iframe跳轉(zhuǎn),而父頁面沒有刷新。這使得上傳結(jié)束后,服務(wù)器處理結(jié)果返回到動(dòng)態(tài)iframe窗口而沒有刷新頁面;

      <input type="file" id="j-upload-input" name="upload"/>
      
      var createUploadForm = function (id, fileElementId) {  
            //create form    
          var formId = 'jUploadForm' + id;    
          var fileId = 'jUploadFile' + id;
          var form = $('<form  action="" method="POST" name="' + formId + '" id="' + formId + '" enctype="multipart/form-data"></form>');    
          var oldElement = $('#' + fileElementId);    
          var newElement = $(oldElement).clone();    
          $(oldElement).attr('id', fileId);     
          $(oldElement).before(newElement);     
          $(oldElement).appendTo(form);    
          $(form).css('position', 'absolute');    
          $(form).css('top', '-1200px');    
          $(form).css('left', '-1200px');    
          $(form).appendTo('body');    
          return form;
      }
      var createUploadIframe = function (id) {    
      //create frame    
      var frameId = 'jUploadFrame' + id;    
      var iframeHtml = '<iframe id="' + frameId + '" name="' + frameId + '" style="position:absolute; top:-9999px; left:-9999px"' + ' src="' + '" />';    
      $(iframeHtml).appendTo(document.body);    
      return jQuery('#' + frameId).get(0);
      }
      var actionURL = "/fileUpload";
      $('#j-upload-input').change(function () {    
          var id = new Date().getTime() ;   
          var frameId = 'jUploadFrame' + id;    
          var formId = 'jUploadForm' + id;    
          var form = createUploadForm(id, "j-upload-input");
          var frame = createUploadIframe(id);   
          form.appendTo(document.body);   
          var form = $('#' + formId);    
          $(form).attr('action', actionURL);   
          $(form).attr('method', 'POST');    
          $(form).attr('target', frameId);    
          $(form).attr('enctype', 'multipart/form-data');    
          $(form).submit();
      })
      

      上述程序?qū)崿F(xiàn)了,id值為“j-upload-input”的input元素,在觸發(fā)文件選擇時(shí)(onchange事件),動(dòng)態(tài)創(chuàng)建一個(gè)form元素和一個(gè)iframe元素,input加入一個(gè)動(dòng)態(tài)創(chuàng)建form元素,并將form元素的target值指向iframe元素,最終結(jié)果實(shí)現(xiàn)了觸發(fā)input文件選擇,發(fā)送文件請(qǐng)求,但是頁面不刷新; 文件上傳不刷新

      結(jié)果處理

      通過iframe+form上傳,上傳結(jié)果處理需要前后端配合; 1.前后端預(yù)先約定好回調(diào)函數(shù)名; 例如,在當(dāng)前頁面中定義好上傳的回調(diào)函數(shù)。 function uploadCallBack (resp){...}

      服務(wù)返回的數(shù)據(jù)形式可以為:

       <script type="text/javascript">
          window.top.window['uploadCallBack'](resp);
        </script>
      

      通過window.top.window[uploadCallBack]可以調(diào)用到iframe父級(jí)元素中定義的uploadCallBack方法,也就是預(yù)先定義的回調(diào)處理; 2.前端頁可以監(jiān)聽frame 的onLoad確定是否請(qǐng)求超時(shí)和后端是否給予返回;

      通過FormData ajax方式

      XMLHttpRequest Level 2添加了一個(gè)新的接口FormData利用FormData對(duì)象,我們可以通過JavaScript用一些鍵值對(duì)來模擬一系列表單控件,我們還可以使用XMLHttpRequest的send() 方法來異步的提交這個(gè)"表單"。比起普通的ajax,使用FormData 的最大優(yōu)點(diǎn)就是我們可以異步上傳一個(gè)二進(jìn)制文件。

      構(gòu)建一個(gè)FormData并上傳文件

      var xhr = new XMLHttpRequest();
      var formData = new FormData();
      for (var key in params) {    
          formData.append(key, params[key]);
      }
      formData.append(fileName, fileObj);
      xhr.open(this.options.method, this.options.url, true);
      xhr.send(formData);
      

      通過拖拽操作選擇文件

      現(xiàn)在很多上傳功能都包含拖拽上傳,實(shí)現(xiàn)上傳功能首先要?jiǎng)?chuàng)建一個(gè)拖放操作的目的區(qū)域并應(yīng)用程序的設(shè)計(jì)來決定哪部分的內(nèi)容接受 drop;

      var dragArea;
      if ((dragArea = document.getElementById("j-drag-area")) && dragArea.addEventListener) {    
          dragArea.addEventListener("dragover", dragoverHandler, false);    
          dragArea.addEventListener("dragleave", dragleaveHandler, false);    
          dragArea.addEventListener("drop", dropHandler, false);}
      

      在例子中定義了id值為“j-drag-area”的元素為文件拖拽上傳受理區(qū)域,我們需要在該元素上綁定 dragover,dragleave,和drop 事件。 其中dragover,當(dāng)拖拽中的鼠標(biāo)移動(dòng)經(jīng)過一個(gè)元素的時(shí)候觸發(fā),可以做一些文件經(jīng)過,拖拽區(qū)域高亮處理。dragleave當(dāng)拖拽中的鼠標(biāo)離開元素時(shí)觸發(fā)。監(jiān)聽器需要將作為可釋放反饋的高亮或插入標(biāo)記去除。drop 這個(gè)事件在拖拽操作結(jié)束釋放時(shí)于釋放元素上觸發(fā)。一個(gè)監(jiān)聽器用來響應(yīng)接收被拖拽的數(shù)據(jù)并插入到釋放之地。

      function dragoverHandler(event) {    
      event.stopPropagation();   
       event.preventDefault();    
      ......
      //這里可以添加拖拽區(qū)域背景高亮處理樣式
      }
      function dragleaveHandler(event) {    
      event.stopPropagation();    
      event.preventDefault();    
      ......
      //這里可以異常拖拽區(qū)域背景高亮處理的樣式
      }
      function dropHandler(event) {   
       event.stopPropagation();   
       event.preventDefault();    
      //獲取并處理文件
      var dt = event.dataTransfer; 
      var files = dt.files; 
      handleFiles(files);
      }
      

      在代碼中的event.dataTransfer.files屬性表示被拖動(dòng)到瀏覽器窗口中的文件列表。

      文件上傳進(jìn)度

      XMLHttpRequest Level 2中,傳送數(shù)據(jù)的時(shí)候,有一個(gè)progress事件,上傳數(shù)據(jù)progress事件屬于XMLHttpRequest.upload對(duì)象,上傳數(shù)據(jù)過程中會(huì)觸發(fā)。事件回調(diào)函數(shù)中可以使用事件event的下列屬性:event.total是需要傳輸?shù)目傋止?jié);event.loaded是已經(jīng)傳輸?shù)淖止?jié);如果event.lengthComputable不為真,則event.total等于0。

      var xhr = new XMLHttpRequest(),        
      formData = new FormData();
      xhr.onreadystatechange = function () {    
      if (xhr.readyState == 4) {// 4 = "loaded"        
      onComplete(xhr);//上傳完成處理    }};
      xhr.upload.onprogress = function (e) {    
      if (e.lengthComputable) {        
      onProgressHandler( e.loaded, e.total, xhr);        
      //e.total是需要傳輸?shù)目傋止?jié),e.loaded是已經(jīng)傳輸?shù)淖止?jié)。但如果e.lengthComputable值為false,則e.total等于0。       
      // 通過(e.loaded/e.total)即可得到上傳比例,可以用這個(gè)已上傳比例去更新進(jìn)度條啦    
      }
      };
      xhr.open(this.options.method, this.options.url, true);
      for (var key in params) {    
      formData.append(key, params[key]);
      }
      formData.append(fileName, fileObj);
      xhr.send(formData);
      

      對(duì)于低版本瀏覽器則可以用通過輪詢的方式獲取上傳進(jìn)度;

      文件MD5

      HTML5 DOM新增的File API,使得JavaScript操作文件成為可能;

      File API 要在瀏覽器中對(duì)文件進(jìn)行md5,基本思路就是使用HTML5的FileReader接口把文件讀取到內(nèi)存,然后獲取文件的二進(jìn)制內(nèi)容,最后再進(jìn)行md5。 讀取文件

      file = document.getElementById("file").files[0];
      

      文件切割

      //file的slice方法,注意它的兼容性,在不同瀏覽器的寫法不同
      blobSlice = File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice
      //然后指定file和開始結(jié)束的片段,就可以得到切割的文件了。
      blobSlice.call(file, start, end);
      

      計(jì)算文件MD5

      spark = new SparkMD5();
      spark.appendBinary(filepice1);
      spark.appendBinary(filepice2);
      spark.appendBinary(filepice3);
      ....//所有的分片處理好之后調(diào)用下面的方法就能獲取到文件的MD5了
      spark.end()
      

      附上js-spark-md5計(jì)算文件MD5方法 Demo源碼

      document.getElementById('file').addEventListener('change',   function () { 
          var blobSlice = File.prototype.slice || File.prototype.mozSlice ||     File.prototype.webkitSlice, 
          file = this.files[0],
           chunkSize = 2097152, // Read in chunks of 2MB 
          chunks = Math.ceil(file.size / chunkSize),
           currentChunk = 0, 
          spark = new SparkMD5.ArrayBuffer(), 
          fileReader = new FileReader(); 
          fileReader.onload = function (e) { 
              console.log('read chunk nr', currentChunk + 1, 'of', chunks); 
              spark.append(e.target.result); // Append array buffer 
              currentChunk++;
               if (currentChunk < chunks) { 
                  loadNext(); 
              } else {
                   console.log('finished loading'); 
                  console.info('computed hash', spark.end()); 
                  // Compute hash
               } 
          }; 
          fileReader.onerror = function () { 
              console.warn('oops, something went wrong.');
           };
           function loadNext() {
               var start = currentChunk * chunkSize,
               end = ((start + chunkSize) >= file.size) ? file.size : start +    chunkSize;
               fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
           } 
          loadNext();
      });
      

      圖片預(yù)覽

      如果上傳的文件是圖片類型,上傳插件通常會(huì)提供圖片預(yù)覽功能,圖片預(yù)覽首先要判斷文件類型是否為圖片類型,可以通過正則表達(dá)式匹配判斷

      var imageType = /^image\//; 
      if ( imageType.test(file.type) ) { 
          //是圖片;
       }
      

      讀取和顯示圖片,首先要構(gòu)建一個(gè)img元素標(biāo)簽,給img的src屬性賦值;讀取圖片文件可用new FileReader()對(duì)象的readAsDataURL(file)方法,方法返回文件的base64編碼串。 例子: html

      <input type="file" onchange="previewFile()"><br>
      <img src="" height="200" alt="Image preview...">
      
      function previewFile() { 
          var preview = document.querySelector('img'); 
          var file = document.querySelector('input[type=file]').files[0]; 
          var reader = new FileReader(); 
          reader.addEventListener("load", function () { 
              preview.src = reader.result; 
          }, false); 
          if (file) { 
          reader.readAsDataURL(file); 
          }
      }
      

      參考:

      FormData Using XMLHttpRequest HTML5 file api 讀取文件MD5碼 文件上傳的漸進(jìn)式增強(qiáng) 在web應(yīng)用中使用文件 拖放操作 在瀏覽器端獲取文件的MD5值 js-spark-md5

      42 16
      譚雪微 , 宋俊剛 , 方向劉伶令 , 祝娜 , 呂廣川 , 魏天堯韓平 , 王萃 , 張祥潤 , 王艷 , 尹紅煉毛崯杰 , 朱潔 , 鞠智寬吳笛 , 李仲浩 , 霍寶平張大展 , 孫圣翔劉詩川 , 陸建浩 , 方彬 , 張成 , yixin.libinbin蘇東樂 , 謝壽保 , 孫飛 , 王飛 , 吳碩碩 , 李福泉 , 崔奇凡 , 張展宇 , 郝緒彤 , 沈洪梁胡兵心 , 周潔 , 劉一帝王夢(mèng) , 程霖趙雨森 , 朱立蕾
      查看更多
      ...共42人
      評(píng)論內(nèi)容
      2017-02-08 16:06
      回復(fù)
      龍運(yùn)霞
      回復(fù)孫圣翔:隨便轉(zhuǎn)發(fā)
      2017-02-06 09:39
      回復(fù)
      孫圣翔
      好全面的總結(jié),我可以轉(zhuǎn)發(fā)到外網(wǎng)嗎?

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多