從HTML5提供了video標(biāo)簽,在網(wǎng)頁中播放視頻已經(jīng)變成一個非常簡單的事,只要一個video標(biāo)簽,src屬性設(shè)置為視頻的地址就完事了。由于src指向真實的視頻網(wǎng)絡(luò)地址,在早期一般網(wǎng)站資源文件不怎么通過referer設(shè)置防盜鏈,當(dāng)我們拿到視頻的地址后可以隨意的下載或使用(每次放假回家,就會有親戚找我?guī)兔囊恍┮曨l網(wǎng)站上下東西)。
目前的云存儲服務(wù)商大部分都支持referer防盜鏈。其原理就是在訪問資源時,請求頭會帶上發(fā)起請求的頁面地址,判斷其不存在(表示直接訪問圖片地址)或不在白名單內(nèi),即為盜鏈。
可是從某個時間開始我們打開調(diào)試工具去看各大視頻網(wǎng)站的視頻src會發(fā)現(xiàn),它們統(tǒng)統(tǒng)變成了這樣的形式。
拿b站的一個視頻來看,紅框中的視頻地址,這個blob是個什么東西?。
其實這個Blob URL也不是什么新技術(shù),國內(nèi)外出來都有一陣子了,但是網(wǎng)上的相關(guān)的文章不多也不是很詳細(xì),今天就和大家一起分享學(xué)習(xí)一下。
Blob和ArrayBuffer
最早是數(shù)據(jù)庫直接用Blob來存儲二進(jìn)制數(shù)據(jù)對象,這樣就不用關(guān)注存儲數(shù)據(jù)的格式了。在web領(lǐng)域,Blob對象表示一個只讀原始數(shù)據(jù)的類文件對象,雖然是二進(jìn)制原始數(shù)據(jù)但是類似文件的對象,因此可以像操作文件對象一樣操作Blob對象。
ArrayBuffer對象用來表示通用的、固定長度的原始二進(jìn)制數(shù)據(jù)緩沖區(qū)。我們可以通過new ArrayBuffer(length)來獲得一片連續(xù)的內(nèi)存空間,它不能直接讀寫,但可根據(jù)需要將其傳遞到TypedArray視圖或 DataView 對象來解釋原始緩沖區(qū)。實際上視圖只是給你提供了一個某種類型的讀寫接口,讓你可以操作ArrayBuffer里的數(shù)據(jù)。TypedArray需指定一個數(shù)組類型來保證數(shù)組成員都是同一個數(shù)據(jù)類型,而DataView數(shù)組成員可以是不同的數(shù)據(jù)類型。
TypedArray視圖的類型數(shù)組對象有以下幾個:
Blob與ArrayBuffer的區(qū)別是,除了原始字節(jié)以外它還提供了mime type作為元數(shù)據(jù),Blob和ArrayBuffer之間可以進(jìn)行轉(zhuǎn)換。
File對象其實繼承自Blob對象,并提供了提供了name , lastModifiedDate, size ,type 等基礎(chǔ)元數(shù)據(jù)。
創(chuàng)建Blob對象并轉(zhuǎn)換成ArrayBuffer:
//創(chuàng)建一個以二進(jìn)制數(shù)據(jù)存儲的html文件 const text="<div>hello world</div>"; const blob=new Blob([text], { type: "text/html" }); // Blob {size: 22, type: "text/html"} //以文本讀取 const textReader=new FileReader(); textReader.readAsText(blob); textReader.onload=function() { console.log(textReader.result); // <div>hello world</div> }; //以ArrayBuffer形式讀取 const bufReader=new FileReader(); bufReader.readAsArrayBuffer(blob); bufReader.onload=function() { console.log(new Uint8Array(bufReader.result)); // Uint8Array(22) [60, 100, 105, 118, 62, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 60, 47, 100, 105, 118, 62] };
創(chuàng)建一個相同數(shù)據(jù)的ArrayBuffer,并轉(zhuǎn)換成Blob:
//我們直接創(chuàng)建一個Uint8Array并填入上面的數(shù)據(jù) const u8Buf=new Uint8Array([60, 100, 105, 118, 62, 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 60, 47, 100, 105, 118, 62]); const u8Blob=new Blob([u8Buf], { type: "text/html" }); // Blob {size: 22, type: "text/html"} const textReader=new FileReader(); textReader.readAsText(u8Blob); textReader.onload=function() { console.log(textReader.result); // 同樣得到div>hello world</div> };
更多Blob和ArrayBuffer的相關(guān)內(nèi)容可以參看下面的資料:
URL.createObjectURL
video標(biāo)簽,audio標(biāo)簽還是img標(biāo)簽的src屬性,不管是相對路徑,絕對路徑,或者一個網(wǎng)絡(luò)地址,歸根結(jié)底都是指向一個文件資源的地址。既然我們知道了Blob其實是一個可以當(dāng)作文件用的二進(jìn)制數(shù)據(jù),那么只要我們可以生成一個指向Blob的地址,是不是就可以用在這些標(biāo)簽的src屬性上,答案肯定是可以的,這里我們要用到的就是URL.createObjectURL()。
const objectURL=URL.createObjectURL(object); //blob:http://localhost:1234/abcedfgh-1234-1234-1234-abcdefghijkl 復(fù)制代碼
這里的object參數(shù)是用于創(chuàng)建URL的File對象、Blob 對象或者 MediaSource 對象,生成的鏈接就是以blob:開頭的一段地址,表示指向的是一個二進(jìn)制數(shù)據(jù)。
其中l(wèi)ocalhost:1234是當(dāng)前網(wǎng)頁的主機(jī)名稱和端口號,也就是location.host,而且這個Blob URL是可以直接訪問的。需要注意的是,即使是同樣的二進(jìn)制數(shù)據(jù),每調(diào)用一次URL.createObjectURL方法,就會得到一個不一樣的Blob URL。這個URL的存在時間,等同于網(wǎng)頁的存在時間,一旦網(wǎng)頁刷新或卸載,這個Blob URL就失效。
通過URL.revokeObjectURL(objectURL) 釋放一個之前已經(jīng)存在的、通過調(diào)用 URL.createObjectURL() 創(chuàng)建的 URL 對象。當(dāng)你結(jié)束使用某個 URL 對象之后,應(yīng)該通過調(diào)用這個方法來讓瀏覽器知道不用在內(nèi)存中繼續(xù)保留對這個文件的引用了,允許平臺在合適的時機(jī)進(jìn)行垃圾收集。
如果是以文件協(xié)議打開的html文件(即url為file://開頭),則地址中http://localhost:1234會變成null,而且此時這個Blob URL是無法直接訪問的。
實戰(zhàn)一:上傳圖片預(yù)覽
有時我們通過input上傳圖片文件之前,會希望可以預(yù)覽一下圖片,這個時候就可以通過前面所學(xué)到的東西實現(xiàn),而且非常簡單。
html
<input id="upload" type="file" /> <img id="preview" src="" alt="預(yù)覽"/>
javascript
const upload=document.querySelector("#upload"); const preview=document.querySelector("#preview"); upload.onchange=function() { const file=upload.files[0]; //File對象 const src=URL.createObjectURL(file); preview.src=src; };
這樣一個圖片上傳預(yù)覽就實現(xiàn)了,同樣這個方法也適用于上傳視頻的預(yù)覽。
實戰(zhàn)二:以Blob URL加載網(wǎng)絡(luò)視頻
現(xiàn)在我們有一個網(wǎng)絡(luò)視頻的地址,怎么能將這個視頻地址變成Blob URL是形式呢,思路肯定是先要拿到存儲這個視頻原始數(shù)據(jù)的Blob對象,但是不同于input上傳可以直接拿到File對象,我們只有一個網(wǎng)絡(luò)地址。
我們知道平時請求接口我們可以使用xhr(jquery里的ajax和axios就是封裝的這個)或fetch,請求一個服務(wù)端地址可以返回我們相應(yīng)的數(shù)據(jù),那如果我們用xhr或者fetch去請求一個圖片或視頻地址會返回什么呢?當(dāng)然是返回圖片和視頻的數(shù)據(jù),只不過要設(shè)置正確responseType才能拿到我們想要的格式數(shù)據(jù)。
function ajax(url, cb) { const xhr=new XMLHttpRequest(); xhr.open("get", url); xhr.responseType="blob"; // ""|"text"-字符串 "blob"-Blob對象 "arraybuffer"-ArrayBuffer對象 xhr.onload=function() { cb(xhr.response); }; xhr.send(); }
注意XMLHttpRequest和Fetch API請求會有跨域問題,可以通過跨域資源共享(CORS)解決。
看到responseType可以設(shè)置blob和arraybuffer我們應(yīng)該就有譜了,請求返回一個Blob對象,或者返回ArrayBuffer對象轉(zhuǎn)換成Blob對象,然后通過createObjectURL生成地址賦值給視頻的src屬性就可以了,這里我們直接請求一個Blob對象。
ajax('video.mp4', function(res){ const src=URL.createObjectURL(res); video.src=src; })
用調(diào)試工具查看視頻標(biāo)簽的src屬性已經(jīng)變成一個Blob URL,表面上看起來是不是和各大視頻網(wǎng)站形式一致了,但是考慮一個問題,這種形式要等到請求完全部視頻數(shù)據(jù)才能播放,小視頻還好說,要是視頻資源大一點(diǎn)豈不爆炸,顯然各大視頻網(wǎng)站不可能這么干。
解決這個問題的方法就是流媒體,其帶給我們最直觀體驗就是使媒體文件可以邊下邊播(像我這樣的90后男性最早體會到流媒體好處的應(yīng)該是源于那款快子頭的播放器),web端如果要使用流媒體,有多個流媒體協(xié)議可以供我們選擇。
HLS和MPEG DASH
HLS (HTTP Live Streaming), 是由 Apple 公司實現(xiàn)的基于 HTTP 的媒體流傳輸協(xié)議。HLS以ts為傳輸格式,m3u8為索引文件(文件中包含了所要用到的ts文件名稱,時長等信息,可以用播放器播放,也可以用vscode之類的編輯器打開查看),在移動端大部分瀏覽器都支持,也就是說你可以用video標(biāo)簽直接加載一個m3u8文件播放視頻或者直播,但是在pc端,除了蘋果的Safari,需要引入庫來支持。
用到此方案的視頻網(wǎng)站比如優(yōu)酷,可以在視頻播放時通過調(diào)試查看Network里的xhr請求,會發(fā)現(xiàn)一個m3u8文件,和每隔一段時間請求幾個ts文件。
但是除了HLS,還有Adobe的HDS,微軟的MSS,方案一多就要有個標(biāo)準(zhǔn)點(diǎn)的東西,于是就有了MPEG DASH。
DASH(Dynamic Adaptive Streaming over HTTP) ,是一種在互聯(lián)網(wǎng)上傳送動態(tài)碼率的Video Streaming技術(shù),類似于蘋果的HLS,DASH會通過media presentation description (MPD)將視頻內(nèi)容切片成一個很短的文件片段,每個切片都有多個不同的碼率,DASH Client可以根據(jù)網(wǎng)絡(luò)的情況選擇一個碼率進(jìn)行播放,支持在不同碼率之間無縫切換。
Youtube,B站都是用的這個方案。這個方案索引文件通常是mpd文件(類似HLS的m3u8文件功能),傳輸格式推薦的是fmp4(Fragmented MP4),文件擴(kuò)展名通常為.m4s或直接用.mp4。所以用調(diào)試查看b站視頻播放時的網(wǎng)絡(luò)請求,會發(fā)現(xiàn)每隔一段時間有幾個m4s文件請求。
不管是HLS還是DASH們,都有對應(yīng)的庫甚至是高級的播放器方便我們使用,但我們其實是想要學(xué)習(xí)一點(diǎn)實現(xiàn)。其實拋開掉索引文件的解析拿到實際媒體文件的傳輸?shù)刂罚瑪[在我們面前的只有一個如何將多個視頻數(shù)據(jù)合并讓video標(biāo)簽可以無縫播放。
與之相關(guān)的一篇B站文章推薦給感興趣的朋友:我們?yōu)槭裁词褂肈ASH
MediaSource
video標(biāo)簽src指向一個視頻地址,視頻播完了再將src修改為下一段的視頻地址然后播放,這顯然不符合我們無縫播放的要求。其實有了我們前面Blob URL的學(xué)習(xí),我們可能就會想到一個思路,用Blob URL指向一個視頻二進(jìn)制數(shù)據(jù),然后不斷將下一段視頻的二進(jìn)制數(shù)據(jù)添加拼接進(jìn)去。這樣就可以在不影響播放的情況下,不斷的更新視頻內(nèi)容并播放下去,想想是不是有點(diǎn)流的意思出來了。
要實現(xiàn)這個功能我們要通過MediaSource來實現(xiàn),MediaSource接口功能也很純粹,作為一個媒體數(shù)據(jù)容器可以和HTMLMediaElement進(jìn)行綁定。基本流程就是通過URL.createObjectURL創(chuàng)建容器的BLob URL,設(shè)置到video標(biāo)簽的src上,在播放過程中,我們?nèi)匀豢梢酝ㄟ^MediaSource.appendBuffer方法往容器里添加數(shù)據(jù),達(dá)到更新視頻內(nèi)容的目的。
實現(xiàn)代碼如下:
const video=document.querySelector('video'); //視頻資源存放路徑,假設(shè)下面有5個分段視頻 video1.mp4 ~ video5.mp4,第一個段為初始化視頻init.mp4 const assetURL="http://www.demo.com"; //視頻格式和編碼信息,主要為判斷瀏覽器是否支持視頻格式,但如果信息和視頻不符可能會報錯 const mimeCodec='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'; if ('MediaSource' in window && MediaSource.isTypeSupported(mimeCodec)) { const mediaSource=new MediaSource(); video.src=URL.createObjectURL(mediaSource); //將video與MediaSource綁定,此處生成一個Blob URL mediaSource.addEventListener('sourceopen', sourceOpen); //可以理解為容器打開 } else { //瀏覽器不支持該視頻格式 console.error('Unsupported MIME type or codec: ', mimeCodec); } function sourceOpen () { const mediaSource=this; const sourceBuffer=mediaSource.addSourceBuffer(mimeCodec); let i=1; function getNextVideo(url) { //ajax代碼實現(xiàn)翻看上文,數(shù)據(jù)請求類型為arraybuffer ajax(url, function(buf) { //往容器中添加請求到的數(shù)據(jù),不會影響當(dāng)下的視頻播放。 sourceBuffer.appendBuffer(buf); }); } //每次appendBuffer數(shù)據(jù)更新完之后就會觸發(fā) sourceBuffer.addEventListener("updateend", function() { if (i===1) { //第一個初始化視頻加載完就開始播放 video.play(); } if (i < 6) { //一段視頻加載完成后,請求下一段視頻 getNextVideo(`${assetURL}/video${i}.mp4`); } if (i===6) { //全部視頻片段加載完關(guān)閉容器 mediaSource.endOfStream(); URL.revokeObjectURL(video.src); //Blob URL已經(jīng)使用并加載,不需要再次使用的話可以釋放掉。 } i++; }); //加載初始視頻 getNextVideo(`${assetURL}/init.mp4`); };
這段代碼修改自MDN的MediaSource詞條中的示例代碼,原例子中只有加載一段視頻,我修改為了多段視頻,代碼里面很多地方還可以優(yōu)化精簡,這里沒做就當(dāng)是為了方便我們看邏輯。
此時我們已經(jīng)基本實現(xiàn)了一個簡易的流媒體播放功能,如果愿意可以再加入m3u8或mpd文件的解析,設(shè)計一下UI界面,就可以實現(xiàn)一個流媒體播放器了。
最后提一下一個坑,很多人跑了MDN的MediaSource示例代碼,可能會發(fā)現(xiàn)使用官方提供的視頻是沒問題的,但是用了自己的mp4視頻就會報錯,這是因為fmp4文件擴(kuò)展名通常為.m4s或直接用.mp4,但卻是特殊的mp4文件。
Fragmented MP4
通常我們使用的mp4文件是嵌套結(jié)構(gòu)的,客戶端必須要從頭加載一個 MP4 文件,才能夠完整播放,不能從中間一段開始播放。而Fragmented MP4(簡稱fmp4),就如它的名字碎片mp4,是由一系列的片段組成,如果服務(wù)器支持 byte-range 請求,那么,這些片段可以獨(dú)立的進(jìn)行請求到客戶端進(jìn)行播放,而不需要加載整個文件。
我們可以通過這個網(wǎng)站判斷一個mp4文件是否為Fragmented MP4,網(wǎng)站地址。
我們通過FFmpeg或Bento4的mp4fragment來將普通mp4轉(zhuǎn)換為Fragmented MP4,兩個工具都是命令行工具,按照各自系統(tǒng)下載下來對應(yīng)的壓縮包,解壓后設(shè)置環(huán)境變量指向文件夾中的bin目錄,就可以使用相關(guān)命令了。
Bento4的mp4fragment,沒有太多參數(shù),命令如下:
mp4fragment video.mp4 video-fragmented.mp4
FFmpeg會需要設(shè)置一些參數(shù),命令如下:
ffmpeg -i video.mp4 -movflags empty_moov+default_base_moof+frag_keyframe video-fragmented.mp4
Tips:網(wǎng)上大部分的資料中轉(zhuǎn)換時是不帶default_base_moof這個參數(shù)的,雖然可以轉(zhuǎn)換成功,但是經(jīng)測試如果不添加此參數(shù)網(wǎng)頁中MediaSource處理視頻時會報錯。
視頻的切割分段可以使用Bento4的mp4slipt,命令如下:
mp4split video.mp4 --media-segment video-%llu.mp4 --pattern-parameters N
最后
之所以寫這篇文章其實是之前公司有個需求要了解一下Blob URL,稍微看了一下,后來不了了之。這次忙里偷閑重拾起來把它搞清楚,一邊學(xué)習(xí)一邊記錄,這篇文章中的很多點(diǎn)展開了其實有很多內(nèi)容,希望大家看了這篇文章能夠有所啟發(fā)或引起興趣,我的目的也就達(dá)到了,另外視頻這方面的東西真的是有點(diǎn)深的,文章中如果有錯誤和疏漏也歡迎大家指出,我將及時修正。
作者:wangzy2019
鏈接:https://juejin.im/post/5d1ea7a8e51d454fd8057bea
來源:掘金
lob(BinaryLargeObject)術(shù)語最初來自數(shù)據(jù)庫(oracle中也有類似的欄位類型。),早期數(shù)據(jù)庫因為要存儲聲音、圖片、以及可執(zhí)行程序等二進(jìn)制數(shù)據(jù)對象所以給該類對象取名為Blob。
在Web領(lǐng)域,Blob被定義為包含只讀數(shù)據(jù)的類文件對象。Blob中的數(shù)據(jù)不一定是js原生數(shù)據(jù)形式。常見的File接口就繼承自Blob,并擴(kuò)展它用于支持用戶系統(tǒng)的本地文件。
構(gòu)建一個Blob對象通常有三種方式:
用法:新方法創(chuàng)建Blob對象(構(gòu)造函數(shù)來構(gòu)建)
構(gòu)造函數(shù),接受兩個參數(shù)
第一個參數(shù):為一個數(shù)據(jù)序列,可以是任意格式的值,例如,任意數(shù)量的字符串,Blobs以及ArrayBuffers。
第二個參數(shù):用于指定將要放入Blob中的數(shù)據(jù)的類型(MIME)(后端可以通過枚舉MimeType,獲取對應(yīng)類型:
Blob對象的基本屬性:
原生對象構(gòu)建Blob
提示出錯:
原因在于Blob構(gòu)造函數(shù)要求第一個參數(shù)必須是數(shù)組,而這里第一個參數(shù)既不是一個數(shù)組,也沒有可索引的屬性。既然這里提到了對象的可索引屬性,讓我聯(lián)想到了類數(shù)組的概念,而Arguments就是一個很好的例子。來試一試:
可以看到即使是類數(shù)組對象,而數(shù)組元素類型是Number也能得出正確的結(jié)論,猜想大概是由于構(gòu)造函數(shù)內(nèi)部把Number轉(zhuǎn)化為String的緣故吧!
再來試一試其他的參數(shù)類型:
blob.type等于application/json沒問題。arg轉(zhuǎn)為字符串后的長度為16加上制表符\t的寬度4個字節(jié)等于20。
Blob對象的基本方法:
大文件分割(slice()方法),slice方法與數(shù)組的slice類似。
slice()方法接受三個參數(shù),起始偏移量,結(jié)束偏移量,還有可選的mime類型。如果mime類型,沒有設(shè)置,那么新的Blob對象的mime類型和父級一樣。
當(dāng)要上傳大文件的時候,此方法非常有用,可以將大文件分割分段,然后各自上傳,因為分割之后的Blob對象和原始的是獨(dú)立存在的。
不過目前瀏覽器實現(xiàn)此方法還沒有統(tǒng)一,火狐使用的是mozSlice(),Chrome使用的是webkitSlice(),其他瀏覽器則正常的方式slice()
可以寫一個兼容各瀏覽器的方法:
利用Blob顯示縮略圖`
由于File對象繼承自Blob,所以我們可以很方便的利用File對象加載本地系統(tǒng)圖片文件,并通過createObjectURL生成一個URL并加以顯示。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持小編。
lob對象介紹
一個Blob對象表示一個不可變的,原始數(shù)據(jù)的類似文件對象。Blob表示的數(shù)據(jù)不一定是一個JavaScript原生格式blob對象本質(zhì)上是js中的一個對象,里面可以儲存大量的二進(jìn)制編碼格式的數(shù)據(jù)。
創(chuàng)建blob對象
創(chuàng)建blob對象本質(zhì)上和創(chuàng)建一個其他對象的方式是一樣的,都是使用Blob()的構(gòu)造函數(shù)來進(jìn)行創(chuàng)建。構(gòu)造函數(shù)接受兩個參數(shù):
第一個參數(shù)為一個數(shù)據(jù)序列,可以是任意格式的值。
第二個參數(shù)是一個包含兩個屬性的對象{type:MIME的類型,endings:決定第一個參數(shù)的數(shù)據(jù)格式,可以取值為"transparent"或者"native"(transparent的話不變,是默認(rèn)值,native的話按操作系統(tǒng)轉(zhuǎn)換)。}
Blob()構(gòu)造函數(shù)允許使用其他對象創(chuàng)建一個Blob對象,比如用字符串構(gòu)建一個blob
既然是對象,那么blob也擁有自己的屬性以及方法
屬性
布爾值,指示Blob.close()是否在該對象上調(diào)用過。關(guān)閉的blob對象不可讀。
Blob對象中所包含數(shù)據(jù)的大?。ㄗ止?jié))。
一個字符串,表明該Blob對象所包含數(shù)據(jù)的MIME類型。如果類型未知,則該值為空字符串。
方法
關(guān)閉Blob對象,以便能釋放底層資源。
返回一個新的Blob對象,包含了源Blob對象中指定范圍內(nèi)的數(shù)據(jù)。其實就是對這個blob中的數(shù)據(jù)進(jìn)行切割,我們在對文件進(jìn)行分片上傳的時候需要使用到這個方法。
看到上面這些方法和屬性,使用過HTML5提供的File接口的應(yīng)該都很熟悉,這些屬性和方法在File接口中也都有。其實File接口就是基于Blob,繼承blob功能并將其擴(kuò)展為支持用戶系統(tǒng)上的文件,也就是說:
File接口中的Flie對象就是繼承與Blob對象。
blob對象的使用
上面說了很多關(guān)于Blob對象的一些概念性的東西,下面我們來看看實際用途。
分片上傳
首先說說分片上傳,我們在進(jìn)行文件上傳的時候,因為服務(wù)器的限制,會限制每一次上傳到服務(wù)器的文件大小不會很大,這個時候我們就需要把一個需要上傳的文件進(jìn)行切割,然后分別進(jìn)行上傳到服務(wù)器。
假如需要做到這一步,我們需要解決兩個問題:
首先怎么切割的問題上面已經(jīng)有過說明,因為File文件對象是繼承與Blob對象的,因此File文件對象也擁有slice這個方法,我們可以使用這個方法將任何一個File文件進(jìn)行切割。
代碼如下:
通過上面的方法。我們就得到了一個切割之后的File對象組成的數(shù)組blobs;
接下來要做的時候就是講這些文件分別上傳到服務(wù)器。
在HTTP1.1以上的協(xié)議中,有Transfer-Encoding這個編碼協(xié)議,用以和服務(wù)器通信,來得知當(dāng)前分片傳遞的文件進(jìn)程。
這樣解決了這兩個問題,我們不僅可以對文件進(jìn)行分片上傳,并且能夠得到文件上傳的進(jìn)度。
粘貼圖片
blob還有一個應(yīng)用場景,就是獲取剪切板上的數(shù)據(jù)來進(jìn)行粘貼的操作。例如通過QQ截圖后,需要在網(wǎng)頁上進(jìn)行粘貼操作。
粘貼圖片我們需要解決下面幾個問題
首先我們可以通過paste事件來監(jiān)聽用戶的粘貼操作:
然后通過事件對象中的clipboardData對象來獲取圖片的文件數(shù)據(jù)。
clipboardData對象介紹
介紹一下clipboardData對象,它實際上是一個DataTransfer類型的對象,DataTransfer是拖動產(chǎn)生的一個對象,但實際上粘貼事件也是它。
clipboardData的屬性介紹
items介紹
items是一個DataTransferItemList對象,自然里面都是DataTransferItem類型的數(shù)據(jù)了。
屬性
items的DataTransferItem有兩個屬性kind和type
方法
在原型上還有一些其他方法,不過在處理剪切板操作的時候一般用不到了。
type介紹
一般types中常見的值有text/plain、text/html、Files。
有了上面這些方法,我們可以解決第二個問題即獲取到剪切板上的數(shù)據(jù)。
最后我們需要將獲取到的數(shù)據(jù)渲染到網(wǎng)頁上。
其實這個本質(zhì)上就是一個類似于上傳圖片本地瀏覽的問題。我們可以直接通過HTML5的File接口將獲取到的文件上傳到服務(wù)器然后通過講服務(wù)器返回的url地址來對圖片進(jìn)行渲染。也可以使用fileRender對象來進(jìn)行圖片本地瀏覽。
fileRender對象簡介
從Blob中讀取內(nèi)容的唯一方法是使用FileReader。
FileReader接口有4個方法,其中3個用來讀取文件,另一個用來中斷讀取。無論讀取成功或失敗,方法并不會返回讀取結(jié)果,這一結(jié)果存儲在result屬性中。
FileReader接口包含了一套完整的事件模型,用于捕獲讀取文件時的狀態(tài)。
通過上面的方法以及事件,我們可以發(fā)現(xiàn),通過readAsDataURL方法及onload事件就可以拿到一個可本地瀏覽圖片的DataURL。
最終代碼如下:
這樣我們就可以監(jiān)聽到用戶的粘貼操作,并且將用戶粘貼的圖片文件實時的渲染到網(wǎng)頁之中了。
總結(jié)
以上是我對Blob對象的一些學(xué)習(xí)分享,希望在實際應(yīng)用上能對大家有所幫助。也希望大家多多支持小編。
*請認(rèn)真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。