談談基於iframe、FormData、FileReader三種無刷新上傳檔案的方法_javascript技巧
發送請求有兩種方式,一種是用ajax,另一種是用form提交,預設的form提交如果不做處理的話,會使頁面重定向。以一個簡單的demo做說明:
html如下圖所示,請求的路徑action為"upload",其它的不做任何處理:
<form method="POST" action="upload" enctype="multipart/form-data"> 名字 <input type="text" name="user"></input> 头像 <input type="file" name="file"></input> <input type="submit" id="_submit" value="提交"></input> </form>
服務端(node)response直接回傳: "Recieved form data",示範如下:
可看到預設情況下,form請求upload的同時重新導向至upload。但是很多情況下是希望form請求像ajax一樣,不會重定向或刷新頁面。像上面的場景,當上傳完成之後,將使用者選擇的頭像顯示在目前頁面。
解決方法第一種是使用html5的FormData,將form裡面的資料封裝到FormData物件裡,再以POST的方式send出去。如下面程式碼所示,對提交按鈕的點選事件做一個回應,程式碼第6行取得到form的DOM對象,然後第8行建構一個FormData的實例,第18行,將form資料傳送出去。
document.getElementById("_submit").onclick = function(event){ //取消掉默认的form提交方式 if(event.preventDefault) event.preventDefault(); else event.returnValue = false; //对于IE的取消方式 var formDOM = document.getElementsByTagName("form")[]; //将form的DOM对象当作FormData的构造函数 var formData = new FormData(formDOM); var req = new XMLHttpRequest(); req.open("POST", "upload"); //请求完成 req.onload = function(){ if(this.status === ){ //对请求成功的处理 } } //将form数据发送出去 req.send(formData); //避免内存泄漏 req = null; }
成功上傳後,服務將返回圖片的存取地址,補充14行對請求成功的處理:在submit按鈕的上方位置顯示上傳的圖片:
var img = document.createElement("img"); img.src = JSON.parse(this.responseText).path; formDOM.insertBefore(img, document.getElementById("_submit"));
範例:
如果使用jQuery,可以把formData當作ajax的data參數,同時設定contentType: false和processData: false,告訴jQuery不要去處理請求頭和傳送的資料。
看起來這種提交方式跟ajax一樣,但是其實並不是完全一樣,form提交的資料格式有三種,如果要上傳文件則必須為multipart/form-data,所以上面的form提交請求裡的http的頭資訊裡面的Content-Type為multipart/form-data,而普通的ajax提交為application/json。 form提交完整的Content-Type如下:
"content-type":"multipart/form-data; boundary=------WebKitFormBoundaryYOE7pWLqdFYSeBFj"
除了multipart/form-data之外,也指定了boundary,這個boundary的功能是用來區分不同的欄位。由於FormData物件是不透明的,呼叫JSON.stringify將會傳回一個空的物件{},同時FormData只提供append方法,所以無法得到FormData實際上傳的內容,但是可以透過分析工具或服務收到的資料來查看。在上面如果上傳一個文字文件,那麼服務收到的POST資料的原始格式是這樣的:
------WebKitFormBoundaryYOE7pWLqdFYSeBFj
Content-Disposition: form-data; name="user"
abc
------WebKitFormBoundaryYOE7pWLqdFYSeBFj
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
這是一個文字檔案的內容。
------WebKitFormBoundaryYOE7pWLqdFYSeBFj--
從上述服務收到的資料看出FormData提交的格式,每個欄位以boundary隔開,最後以--結束。而ajax請求,send出去的資料格式是自訂的,一般都是以key=value中間用&連接:
var req = new XMLHttpRequest(); var sendData = "user=abc&file=这是一个文本文件的内内容"; req.open("POST", "upload"); //发送的数据需要转义,见上面提到的三种格式 req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); req.send(sendData);
服务就会收到和send发出去的字符串一模一样的内容,然后再作参数解析,所以就得统一参数的格式:
user=abc&file=这是一个文本文件的内容
从这里可以看出POST本质上并不比GET安全,POST只是没有将数据放在网址传送而已。
考虑到FormData到了IE10才支持,如果要支持较低版本的IE,那么可以借助iframe。
文中一开始就说,默认的form提交会使页面重定向,而重定向的规则在target中指定,可以和a标签一样指定为"_blank",在新窗口中打开;还可以指定为一个iframe,在该iframe中打开。所以可以弄一个隐藏的iframe,将form的target指向这个iframe,当form请求完成时,返回的数据就会由这个iframe显示,正如上面在新页面显示的:"Recieved form data"。请求完成后,iframe加载完成,触发load事件,在load事件的处理函数里,获取该iframe的内容,从而拿到服务返回的数据了!拿到后再把iframe删掉。
在提交按钮的响应函数里,首先创建一个iframe,设置iframe为不可见,然后再添加到文档里:
var iframe = document.createElement("iframe"); iframe.width = 0; iframe.height = 0; iframe.border = 0; iframe.name = "form-iframe"; iframe.id = "form-iframe"; iframe.setAttribute("style", "width:0;height:0;border:none"); //放到document this.form.appendChild(iframe);
改变form的target为iframe的name值:
this.form.target = "form-iframe";
然后再响应iframe的load事件:
iframe.onload = function(){ var img = document.createElement("img"); //获取iframe的内容,即服务返回的数据 var responseData = this.contentDocument.body.textContent || this.contentWindow.document.body.textContent; img.src = JSON.parse(responseData).path; f.insertBefore(img, document.getElementById("_submit")); //删掉iframe setTimeout(function(){ var _frame = document.getElementById("form-iframe"); _frame.parentNode.removeChild(_frame); }, 100); //如果提示submit函数不存在,请注意form里面是否有id/value为submit的控件 this.form.submit(); }
第二种办法到这里就基本可以了,但是如果看163邮箱或者QQ邮箱上传文件的方式,会发现和上面的两种方法都不太一样。用httpfox抓取请求的数据,会发现上传的内容的格式并不是上面说的用boundary隔开,而是直接把文件的内容POST出去了,而文件名、文件大小等相关信息放在了文件的头部。如163邮箱:
POST Data:
this is a text
Headers:
Mail-Upload-name: content.txt
Mail-Upload-size: 15
可以推测它们应该是直接读取了input文件的内容,然后直接POST出去了。要实现这样的功能,可以借助FileReader,读取input文件的内容,再保留二进制的格式发送出去:
var req = new XMLHttpRequest(); req.open("POST", "upload"); //设置和邮箱一样的Content-Type req.setRequestHeader("Content-Type", "application/octet-stream"); var fr = new FileReader(); fr.onload = function(){ req.sendAsBinary(this.result); } req.onload = function(){ //一样,省略 } //读取input文件内容,放到fileReader的result字段里 fr.readAsBinaryString(this.form["file"].files[0]);
代码第13行执行读文件,读取完毕后触发第6行的load响应函数,第7行以二进制文本形式发送出去。由于sendAsBinary的支持性不是很好,可以自行实现一个:
if(typeof XMLHttpRequest.prototype.sendAsBinary === 'undefined'){ XMLHttpRequest.prototype.sendAsBinary = function(text){ var data = new ArrayBuffer(text.length); var uia = new UintArray(data, ); for (var i = ; i < text.length; i++){ uia[i] = (text.charCodeAt(i) & xff); } this.send(uia); } }
代码的关键在于第6行,将字符串转成8位无符号整型,还原二进制文件的内容。在执行了fr.readAsBinaryString之后,二进制文件的内容将会以utf-8的编码以字符串形式存放到result,上面的第6行代码将每个unicode编码转成整型(&0xff或者parseInt),存放到一个8位无符号整型数组里面,第8行把这个数组发送出去。如果直接send,而不是sendAsBinary,服务收到的数据将无法正常还原成原本的文件。
上面的实现需要考虑文件太大,需分段上传的问题。
关于FileReader的支持性,IE10以上支持,IE9有另外一套File API。
文章讨论了3种办法实现无刷新上传文件,分别是使用iframe、FormData和FileReader,支持性最好是的iframe,但是从体验的效果来看FormData和FileReader更好,因为这两者不用生成一个无用的DOM再删除,其中FormData最简单,而FileReader更加灵活。
下面给大家介绍iframe无刷新上传文件
form.html <form enctype="multipart/form-data" method="post" target="upload" action="upload.php" > <input type="file" name="uploadfile" /> <input type="submit" /> </form> <iframe name="upload" style="display:none"></iframe>

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

內嵌框架在HTML中稱為iframe。標籤指定內容中的一個矩形區域,瀏覽器可以在其中顯示帶有捲軸和邊框的不同文件。若要在目前HTML文檔中嵌入另一個文檔,請使用內嵌框架。可以使用HTMLiframe名稱屬性指定元素的參考。在JavaScript中,對元素的參考也是使用name屬性進行的。 iframe本質上用於在目前顯示的網頁中顯示網頁。包含iframe的文件的URL使用「src」屬性指定。語法以下是HTML的語法<iframesrc="URL"title="d

iframe載入慢的原因主要包括網路延遲、資源載入時間長、載入順序、快取機制以及安全性策略等。詳細介紹:1、網路延遲,當瀏覽器載入一個包含iframe的網頁時,需要發送請求到伺服器取得iframe中的內容,若網路延遲較高,那麼取得內容的時間就會增加,從而導致iframe載入慢;2.資源載入時間長,資源的大小較大或伺服器回應時間較長時,載入速度會更明顯變慢;3、載入順序等等。

iframe中的data-id是指在HTML標籤中使用的自訂屬性,用於儲存特定元素的識別碼。透過使用data-id屬性,可以為iframe元素新增一個唯一的標識符,以便在JavaScript中對其進行操作和存取。 data-id屬性的命名可以根據特定的需求進行自定義,但通常會遵循一些命名規範,以確保其唯一性和易讀性。 data-id屬性也可以用來識別和操作特定的iframe。

當用戶透過Safari瀏覽器存取電子郵件服務時,微軟的Outlook正在macOS上下載一個名為「TokenFactoryIframe」的神秘檔案。發現Outlook在每次造訪時下載的「TokenFactoryIframe」檔案的使用者現在已廣泛報告此問題。 Outlook每隔幾秒鐘或至少每次造訪Apple平台上的Outlook時都會下載此神祕檔案。根據我們的調查結果,這似乎是由發佈到Outlook的伺服器端更新錯誤所引起的問題,與Safari或macOS無關。微軟在一份

可以取代iframe的技術有Ajax、JavaScript庫或框架、Web元件技術、前端路由和伺服器端渲染等。詳細介紹:1、Ajax是一種用來建立動態網頁的技術。它可以透過在後台與伺服器進行資料交換,實現頁面的非同步更新,而無需刷新整個頁面,使用Ajax可以更靈活地載入和顯示內容,不再需要使用iframe來嵌入其他頁面;2、JavaScript庫或框架,如React等等。

iframe的載入事件有onload事件、onreadystatechange事件、onbeforeunload事件、onerror事件、onabort事件等。詳細說明:1、onload事件,指定載入iframe完成後要執行的JavaScript程式碼;2、onreadystatechange事件,指定當iframe狀態變更時要執行的JavaScript程式碼等等。

iframe中的危險主要有:1、安全漏洞,惡意的網頁可以透過iframe載入其他網頁,並進行一些攻擊行為;2、同源策略突破,透過在iframe中載入其他網域下的網頁,能突破同源策略,實現跨域通信,這可能會被惡意攻擊;3、程式碼執行問題,在iframe中載入的網頁可以執行JS程式碼,這可能導致一些安全性問題;4、SEO問題,搜尋引擎可能無法正確解析和索引透過iframe載入的內容等等。

Python中iframe是一種HTML標籤,用於在網頁中嵌入另一個網頁或文件。在Python中,可以使用各種函式庫和框架來處理和操作iframe,其中最常用的是BeautifulSoup函式庫,可以輕鬆地從一個網頁中提取iframe的內容,並對其進行操作和處理。掌握如何處理和操作iframe對於Web開發和資料抓取都是非常有用的。
