面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?

好學習吧丶發表於2020-03-14

今天我也來標題黨一會,用“面試題”蹭一蹭熱度,主要還行想深度剖析一下,檔案上傳,裡面的門道。

1、在web上怎麼實現檔案上傳

在我們使用的各種類庫,框架中檔案上傳長相多樣,百花齊放,但是歸根結底還是離不開一個input標籤,據我所知,所有的檔案上傳都是 html(如有別的方式請大佬指正) input標籤 來實現上傳,寫法如下:

<input type="file" id="file" />
複製程式碼

長相如下:

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?
我們發現最原始的的上傳,其實就就張這樣,樸實無華,後來的那些框架和庫,其實就是隱藏了這個樸實無華的input 而加入了很多華麗的樣式,來操縱這個input

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?
比如你看餓了麼的這個上傳改的相當的花裡胡哨,那我們上傳之後會得到什麼呢?如下圖:

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?
其實這個input的dom物件下面會有個fileList物件,上傳之後會儲存當前這個檔案的所有資訊,實際上,這個fileLlist,就是一個blob物件,

什麼是blob物件

Blob,Binary Large Object的縮寫,代表二進位制型別的大物件。Blob的概念在一些資料庫中有使用到,例如,MYSQL中的BLOB型別就表示二進位制資料的容器。在Web中,Blob型別的物件表示不可變的類似檔案物件的原始資料,通俗點說,就是Blob物件是二進位制資料的容器,用直觀的方式去描述這個二進位制資料 實際上這個fileList就是一個特殊的blob物件

blob如何使用呢?

構建一個Blob物件通常有三種方式:

1、通過Blob物件的建構函式來構建。

2、從已有的Blob物件呼叫slice介面切出一個新的Blob物件。

3、canvas API toBlob方法,把當前繪製資訊轉為一個Blob物件。

下面只看第一種的實現

//建構函式來構建
var blob = new Blob(array[optional], options[optional]);
複製程式碼

建構函式,接受兩個引數

第一個引數:為一個資料序列,可以是任意格式的值,例如,任意數量的字串,Blobs 以及 ArrayBuffers。 第二個引數:用於指定將要放入Blob中的資料的型別(MIME)(後端可以通過列舉MimeType,獲取對應型別

Blob物件的基本屬性:

size :Blob物件包含的位元組數。(只讀)

type : Blob物件包含的資料型別MIME,如果型別未知則返回空字串。

Blob物件的基本方法:

大檔案分割 (slice() 方法),slice方法與陣列的slice類似。

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?

此時一個blob物件就建立好了,在上一部分中,我說fileList是個特殊的blob,你可以發現他其實是在blob的兩大屬性上加了幾個別的屬性,來具體的描述整個檔案

blob有啥作用呢?

1、大檔案上傳

得益於blob的slice方法

當要上傳大檔案的時候,此方法非常有用,可以將大檔案分割分段,然後各自上傳,因為分割之後的 Blob 物件和原始的是獨立存在的。

不過目前瀏覽器實現此方法還沒有統一,火狐使用的是 mozSlice() ,Chrome 使用的是 webkitSlice() ,其他瀏覽器則正常的方式 slice()

//這裡提供一個相容寫法
   function sliceBlob(blob, start, end, type) {
      type = type || blob.type;
      if (blob.mozSlice) {
          return blob.mozSlice(start, end, type);
      } else if (blob.webkitSlice) {
          return blob.webkitSlice(start, end type);
      } else {
          throw new Error("This doesn't work!");
      }
複製程式碼

生成Blob連結,用於隱藏真實連結

某個時間開始我們開啟除錯工具去看各大視訊網站的視訊src會發現,它們統統變成了這樣的形式。

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?
這其實是為了防止盜鏈,而讓後臺傳入的一段二進位制流,我們在給包裝成blob物件,存在記憶體中後,在給轉成可以播放的連結,這樣就有效防止了真是連結的洩露,接下來我們一步步深度剖析(可能有不對之處,請大佬隨之批評指正)! 1、首先第一步,我們得有一個視訊網址,然後,我們通過ajax獲取 2、第二部後臺得給這個連結轉化成一個二進位制的流,我們用blob物件,給他裝進去, 3、用URL.createObjectURL方法,生成一個blob url 4、給這個blob url賦值到video的src上,瀏覽器就會自動解析地址,播放視訊

廢話少說,下上程式碼

       //建立XMLHttpRequest物件
        var xhr = new XMLHttpRequest();
        //配置請求方式、請求地址以及是否同步
        xhr.open('POST', '二進位制流的地址', true);
        //設定請求結果型別為blob
        xhr.responseType = 'blob';
        //請求成功回撥函式
        xhr.onload = function(e) {
            if (this.status == 200) {//請求成功
                //獲取blob物件
                var blob = this.response;
                //獲取blob物件地址,並把值賦給容器
                document.getElementById("video").src = URL.createObjectURL(blob);
            }
        };

複製程式碼

上述程式碼有一個知識點:

URL.createObjectURL

URL.createObjectURL() 靜態方法會建立一個 DOMString,其中包含一個表示引數中給出的物件的URL。這個 URL 的生命週期和建立它的視窗中的 document 繫結。這個新的URL 物件表示指定的 File 物件或 Blob 物件。

也就是說使用這個方法去建立一個DOMstring 引用這這個記憶體中的二進位制流,然後在賦值到video標籤上去就能達到隱藏連結的目的

  var debug = { hello: "world" };
  var blob = new Blob([JSON.stringify(debug, null, 2)], { type: 'application/json' });
   console.log(blob)
   var url = URL.createObjectURL(blob)
   console.log(url)
複製程式碼

如此真實的連結就會被隱藏,並且這個連結是會動態變化,他在被video解析之後指向的地址就是個二進位制檔案的空間地址,看不見摸不著

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?

解析到此,迴歸正題

2、現在上傳圖片的時候提前預覽到圖片怎麼辦?

廢話少說先上程式碼:

//html
 <input type=file>
複製程式碼
//js
//拿到當前的input
  const input = document.querySelector('input[type=file]')
     //監聽改變,如此能拿到檔案上傳的特殊的blob物件,上文介紹過
        input.addEventListener('change', () => {
            //函式被執行,說明已經上傳了檔案
            console.log(input.files)
             //new一個fileReader物件,至於為啥先賣個關子
            const reader = new FileReader()
            reader.readAsDataURL(input.files[0]) // input.files[0]為第一個檔案
            //成功之後賦值
            reader.onload = () => {
                const img = new Image()
                img.src = reader.result
                document.body.appendChild(img)  // reader.result為獲取結果
            }
        }, false)
複製程式碼

效果如下,我們發現我圖片還沒呼叫介面上傳到伺服器呢,就已經能預覽了

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?

下面我們來說一下賣的這個關子

FileReader是啥?

FileReader 物件允許Web應用程式非同步讀取儲存在使用者計算機上的檔案(或原始資料緩衝區)的內容,使用 File 或 Blob 物件指定要讀取的檔案或資料。

下面我們開看看他的一臺方法:

FileReader.readAsArrayBuffer()

開始讀取指定的 Blob中的內容, 一旦完成, result 屬性中儲存的將是被讀取檔案的 ArrayBuffer 資料物件.

**FileReader.readAsBinaryString() **

開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含所讀取檔案的原始二進位制資料。

FileReader.readAsText()

開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含一個字串以表示所讀取的檔案內容。

FileReader.readAsDataURL()

開始讀取指定的Blob中的內容。一旦完成,result屬性中將包含一個data: URL格式的Base64字串以表示所讀取檔案的內容。這個是我們要用到的,因為他的表示方式能被img的src讀取列印結果如下:

面試題:我現在上傳圖片的時候提前預覽到圖片怎麼辦?

相信搞過前端的人都不陌生這些base64的字串,其實就是一段能表示出來的二進位制檔案,至於為啥能解析成圖片這裡就不展開講了,有興趣自行百度,一堆答案

那有人又會問了FileReader.readAsDataURL 和URL.createObjectURL有啥區別呢?

FileReader.readAsDataURL 和URL.createObjectURL區別

1、返回值

  FileReader.readAsDataURL(blob)可以得到一段base64的字串
  URL.createObjectURL(blob)得到的是當前檔案的一個記憶體url
複製程式碼

2、記憶體使用

 FileReader.readAsDataURL(blob)得到一段超長的base64的字串,代表的是個二進位制
  URL.createObjectURL(blob)得到的是一個blob開頭url地址 指向的是這個二進位制地址
複製程式碼

3、記憶體清理

FileReader.readAsDataURL(blob)依照js垃圾回收機制自動從記憶體中清理
 URL.createObjectURL(blob)存在於當前document內,清除方式只有upload()事件或者revokeObjectURL手動清除
複製程式碼

4、執行方式

FileReader.readAsDataURL(blob)通過回撥的方式f返回,非同步執行;
URL.createObjectURL(blob) 直接返回,同步執行;
複製程式碼

5、多個檔案

  FileReader.readAsDataURL(blob)同時處理多個檔案時,需要一個檔案對應一個FileReader物件;
  URL.createObjectURL(blob) 依次返回,沒有影響;
複製程式碼

更多詳細區別參考:blog.csdn.net/qq_36671474…

總結

到這裡啊順利的實現一個提前預覽圖片的功能,核心就是利用前端的一些物件去將檔案資源存存起來,不管存入記憶體或者字串,然後讀取即可,文章屬於現學現賣,記錄學習點滴,不對之處,還請大佬指正!

相關文章