创建在IE中工作的文件上传 [英] create file upload that work in IE
问题描述
请帮忙。你怎么能写一个文件上传脚本,在IE浏览器工作?
类型1
问题不支持文件Api In IE浏览器(诀窍是不使用它?)
<!DOCTYPE html>
< html>
< head runat =server>
< title>< / title>
< script src =Scripts / jquery-1.6.2.jstype =text / javascript>< / script>
< script type =text / javascript>
函数updateSize(){
var nBytes = 0;
var nFiles = 0;
oFiles = document.getElementById(uploadInput)。files;
nFiles = oFiles.length;
for(var nFileId = 0; nFileId< nFiles; nFileId ++){
nBytes + = oFiles [nFileId] .size;
}
var sOutput = nBytes +bytes;
//可选代码为多元逼近
(var aMultiples = [KiB,MiB,GiB,TiB,PiB,EiB,ZiB, (nMultiple ++){
sOutput = nApprox.toFixed(3)++ aMultiples [nMultiple] +((nBytes)/ 1024; nApprox = nBytes / 1024; nApprox> + nBytes +字节);
}
document.getElementById(fileNum)。innerHTML = nFiles;
document.getElementById(fileSize)。innerHTML = sOutput;
}
//可选代码结束
< / script>
< / head>
< body>
< form id =form1runat =server>
< p>< input id =uploadInputtype =filename =myFilesonchange =updateSize();多个/>选定的档案:< span id =fileNum> 0< / span>;总大小:< span id =fileSize> 0< / span>< / p>
< p>< input type =submitvalue =发送文件>< / p>
< / form>
< / body>
< / html>
类型2
问题不支持文档。 getElementById('fileToUpload') .files [0] (是不是获取文件[0]的诀窍?)
< script src =Scripts / jquery-1.4.1.jstype =text / javascript>< / script>
< script type =text / javascript>
函数fileSelected(){
var file = document.getElementById('fileToUpload')。files [0];
if(file){
var fileSize = 0; (file.size> 1024 * 1024)
fileSize =(Math.round(file.size * 100 /(1024 * 1024))/ 100).toString()+'MB';
else
fileSize =(Math.round(file.size * 100/1024)/ 100).toString()+'KB';
document.getElementById('fileName')。innerHTML ='Name:'+ file.name;
document.getElementById('fileSize')。innerHTML ='Size:'+ fileSize;
document.getElementById('fileType')。innerHTML ='Type:'+ file.type;
function uploadFile(){
var fd = new FormData();
fd.append(fileToUpload,document.getElementById('fileToUpload')。files [0]);
var xhr = new XMLHttpRequest();
xhr.upload.addEventListener(progress,uploadProgress,false);
xhr.addEventListener(load,uploadComplete,false);
xhr.addEventListener(error,uploadFailed,false);
xhr.addEventListener(abort,uploadCanceled,false);
$ .post(UploadHandler.ashx);
//xhr.open(\"POST,UploadHandler.ashx);
xhr.send(fd);
函数uploadProgress(evt){
if(evt.lengthComputable){
var percentComplete = Math.round(evt.loaded * 100 / evt.total );
document.getElementById('progressNumber')。innerHTML = percentComplete.toString()+'%';
document.getElementById('prog')。value = percentComplete;
else {
document.getElementById('progressNumber')。innerHTML ='无法计算';
function uploadComplete(evt){
/ *当服务器发送回应时引发此事件* /
alert(evt .target.responseText);
function uploadFailed(evt){
alert(试图上传文件时出现错误。
function uploadCanceled(evt){
alert(上传已被用户取消或浏览器断开连接。
}
< / script>
< / head>
< body>
< form id =form1>
< div>
< label for =fileToUpload>
选择要上传的文件< / label>
< input type =filename =fileToUpload []id =fileToUploadonchange =fileSelected(); />
< / div>
< div id =fileName>
< / div>
< div id =fileSize>
< / div>
< div id =fileType>
< / div>
< div>
< input type =buttononclick =uploadFile()value =上传/>
< / div>
< div id =progressNumber>
< / div>
< progress id =progvalue =0max =100.0>< / progress>
< / form>
< / body>
请帮忙:(
除非使用IE10或其他现代浏览器,否则不能使用这些函数。早期版本的Internet Explorer(和其他浏览器)可能会有变通方法,但是您需要调整背部
为什么不行
直到版本10的Internet Explorer支持一些这些功能,关键的是 FormData 和 FileReader API。您的两个代码片段都依赖于 FileReader
API,第二个一个也依靠 FormData
动态上传文件。
如何判断是否执行代码
我最近编写了一个文件上传小部件,检测这些功能并提供不同的代码等待支持。我使用了 Modernizr 中的功能检测,因为它的测试经常由开源社区进行测试:
var support = {
//文件是否暴露给JS?
//用于Modernizr @
// https://github.com/Modernizr/Modernizr/blob/master/feature-detects/file/api.js
'fileReader': (function testFileReader(){
// Test:寻找全局文件类
return !!(window.File& window.FileList&& window.FileReader);
}()),
//通过formData上传AJAX文件?
'formData':window.FormData!== void 0
};
对于你的 fileSelected
需要 support.fileReader
来评估 true
;对于 uploadFile
,您需要 support.formData
。
不支持这些功能的浏览器的解决方法
如果没有这些功能,则无法从前端读取文件或使用AJAX发送文件。你可以做的是通过你当前页面中隐藏的< iframe />
来发送你的文件,并获得 UploadHandler.ashx
对非XHR请求作出不同的回应。
这个解决方案在技术上是同步的(只发生在另一个隐藏页面),所以你不会获取更新 - 唯一的反馈是上传完成并且服务器已经响应。所以,一旦完全上传,你只能通知用户文件名,大小和成功 - 这可能需要一段时间!
无论如何,这样的HTML看起来如下:
< form
id =form1
runat = server
action =UploadHandler.ashx
target =fileIframe>
name =fileIframe
style =display:none
onload =parseIframeResponse
tabindex = - 1>
< / iframe>
< p>
< input id =uploadInputtype =filename =myFilesonchange =updateSize();多个/>
所选文件:
< span id =fileNum>
0
< / span>
;总大小:
< span id =fileSize>
0
< / span>
< / p>
< p>
< input type =submitvalue =发送文件>
< / p>
< / form>
一些变化:
- 表单现在有一个
target
,这意味着当它将内容发布到action ,它将在那里加载响应,而不是在当前页面上。
- 目标是一个
名称
我们已经包含了iframe。它隐藏着display:none
,并给出了一个负值tabindex
,以确保用户不会绊倒它。它还有一个指定的onload
属性。这是在旧版IE中绑定函数到加载事件的唯一方法。
所以当表单提交时,我们停留在当前页面上,服务器响应在我们隐藏的iframe中加载。当发生这种情况时,浏览器将执行
onload
属性中指定的函数。不幸的是,这意味着该功能需要在全球范围内!
后端内容
我不不知道你的后端是如何工作的,但如果iframe加载响应而不是下载响应,则需要是HTML或纯文本(并且需要在mime类型中指定)。您可以通过查找
X-Requested-With
标头来确定表单是否通过后端的AJAX发布,该标头的值应该是XMLHttpRequest
- 如果不存在,则iframe要求响应,并且需要发送文本或HTML。您可能需要将JSON响应字符串化,该响应将您想要反馈给用户的值(如fileName
,fileSize
&安培;的fileType
。我希望你可以自己做,或者让一个同事来处理。
捕获iframe响应
如上所述,响应处理函数将需要位于全局作用域中,因为旧的IE很古怪,所以
onload
属性要绑定到它。我看到你正在使用jQuery,所以如果你沿着服务器响应的字符串化的路线,你可以写如下函数:
var response = $('#fileIframe')。contents()。find('body')。text();
var object = $ .parseJSON(response);
iframe的问题
load
事件绑定
如前所述,iframe加载事件需要内联绑定为属性iframe本身 - 这是因为IE将无法注册。但是这本身就是个问题,因为即使是一个空的iframe(一个空的或不存在的
src
也会默认为about:blank
)触发一个加载事件。为了缓解这个问题,你需要放弃所有以空字符串作为误报的响应
,并确保你的后端响应某些内容,即使遇到错误。
假设你想使用任何信息来执行你目前得到的一些代码函数
fileSelected
,uploadProgress
等。
这有助于。
编辑1:开箱即用的解决方案
事后看来,为了解决这个问题,我们可以考虑疏忽,不要提到 Fine Uploader ,经过测试( 700多封闭的问题!)和良好的维护独立的插件,旨在实现最好的文件上传exp IE7以上的可能性。还有很好的后端服务器组件选择,包括ASP .NET - 解析上传。编辑2:忽略提及iframe的
>事件。修正了答案。加载
I want to write a file upload script that works in IE but the two types of code that I'm writing have problems in IE.
Please help. How can you write a file upload script that works in IE?
Type 1
Problem Not Support File Api In IE (Is the trick not to use it?)<!DOCTYPE html> <html> <head runat="server"> <title></title> <script src="Scripts/jquery-1.6.2.js" type="text/javascript"></script> <script type="text/javascript"> function updateSize() { var nBytes = 0; var nFiles=0; oFiles = document.getElementById("uploadInput").files; nFiles = oFiles.length; for (var nFileId = 0; nFileId < nFiles; nFileId++) { nBytes += oFiles[nFileId].size; } var sOutput = nBytes + " bytes"; // optional code for multiples approximation for (var aMultiples = ["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"], nMultiple = 0, nApprox = nBytes / 1024; nApprox > 1; nApprox /= 1024, nMultiple++) { sOutput = nApprox.toFixed(3) + " " + aMultiples[nMultiple] + " (" + nBytes + " bytes)"; } document.getElementById("fileNum").innerHTML = nFiles; document.getElementById("fileSize").innerHTML = sOutput; } // end of optional code </script> </head> <body> <form id="form1" runat="server"> <p><input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple /> selected files: <span id="fileNum">0</span>; total size: <span id="fileSize">0</span></p> <p><input type="submit" value="Send file"></p> </form> </body> </html>
Type 2
Problem Not Support document.getElementById('fileToUpload').files[0](Is the trick not to Get Files[0]?)<script src="Scripts/jquery-1.4.1.js" type="text/javascript"></script> <script type="text/javascript"> function fileSelected() { var file = document.getElementById('fileToUpload').files[0]; if (file) { var fileSize = 0; if (file.size > 1024 * 1024) fileSize = (Math.round(file.size * 100 / (1024 * 1024)) / 100).toString() + 'MB'; else fileSize = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB'; document.getElementById('fileName').innerHTML = 'Name: ' + file.name; document.getElementById('fileSize').innerHTML = 'Size: ' + fileSize; document.getElementById('fileType').innerHTML = 'Type: ' + file.type; } } function uploadFile() { var fd = new FormData(); fd.append("fileToUpload", document.getElementById('fileToUpload').files[0]); var xhr = new XMLHttpRequest(); xhr.upload.addEventListener("progress", uploadProgress, false); xhr.addEventListener("load", uploadComplete, false); xhr.addEventListener("error", uploadFailed, false); xhr.addEventListener("abort", uploadCanceled, false); $.post("UploadHandler.ashx"); //xhr.open("POST", "UploadHandler.ashx"); xhr.send(fd); } function uploadProgress(evt) { if (evt.lengthComputable) { var percentComplete = Math.round(evt.loaded * 100 / evt.total); document.getElementById('progressNumber').innerHTML = percentComplete.toString() + '%'; document.getElementById('prog').value = percentComplete; } else { document.getElementById('progressNumber').innerHTML = 'unable to compute'; } } function uploadComplete(evt) { /* This event is raised when the server send back a response */ alert(evt.target.responseText); } function uploadFailed(evt) { alert("There was an error attempting to upload the file."); } function uploadCanceled(evt) { alert("The upload has been canceled by the user or the browser dropped the connection."); } </script> </head> <body> <form id="form1"> <div> <label for="fileToUpload"> Select a File to Upload</label> <input type="file" name="fileToUpload[]" id="fileToUpload" onchange="fileSelected();" /> </div> <div id="fileName"> </div> <div id="fileSize"> </div> <div id="fileType"> </div> <div> <input type="button" onclick="uploadFile()" value="Upload" /> </div> <div id="progressNumber"> </div> <progress id="prog" value="0" max="100.0"></progress> </form> </body>
Please Help :(
解决方案You can't use these functions unless you're using IE10 or another modern browser. Workarounds are possible for earlier versions of Internet Explorer (and other browsers), but you'll need to adjust your back-end code too.
Why it doesn't work
Internet Explorer up until version 10 doesn't support a number of these features, the key ones being the FormData and FileReader APIs. Both of your code snippets rely on the
FileReader
API, and the second one also relies onFormData
to upload the file dynamically.How to determine whether to execute the code or not
I recently wrote a file upload widget that detected these features and served different code depending on support. I used the feature detections from Modernizr, because it's tests are regularly put to the test by the open source community:
var support = { // Are files exposed to JS? // As used by Modernizr @ // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/file/api.js 'fileReader' : (function testFileReader(){ // Test: look for global file class. return !!(window.File && window.FileList && window.FileReader); }()), // AJAX file upload via formData? 'formData' : window.FormData !== void 0 };
For your
fileSelected
function, you'll needsupport.fileReader
to evaluatetrue
; foruploadFile
, you needsupport.formData
.A workaround for browsers that don't support these features
Without these features it's impossible to read a file from the front-end or to send a file using AJAX. What you can do, though, is send your file via a hidden
<iframe/>
inside your current page, and getUploadHandler.ashx
to respond differently to non-XHR requests.This solution is technically synchronous (just happening in another, hidden page), so you won't get updates — the only feedback is when the upload is complete and the server has responded. So you will only be able to inform the user as to file name, size, and success once they have completely uploaded it — which might take a while!
Anyway, the HTML for this would look as follows:
<form id="form1" runat="server" action="UploadHandler.ashx" target="fileIframe"> <iframe name="fileIframe" style="display:none" onload="parseIframeResponse" tabindex="-1"> </iframe> <p> <input id="uploadInput" type="file" name="myFiles" onchange="updateSize();" multiple /> selected files: <span id="fileNum"> 0 </span> ; total size: <span id="fileSize"> 0 </span> </p> <p> <input type="submit" value="Send file"> </p> </form>
A few changes:
- The form now has a
target
, which means that when it posts its content to the URI inaction
, it will load the response in there, as opposed to on the current page. - The target is a
name
reference to an iframe we've included. It is hidden withdisplay:none
, and given a negativetabindex
just to make sure the user doesn't stumble into it. It also has anonload
property specified. This is the only way of binding functions to the load event in older versions of IE.
So when the form is submitted, we stay on the current page and the server response loads in our hidden iframe. When that happens, the browser will execute the function named in the
onload
attribute. Sadly, this means that function needs to be in the global scope!Back-end stuff
I don't know how your back-end works, but if the iframe is to load the response instead of downloading it, it will need to be HTML or plain text (and that will need to be specified in the mime-type). You can tell whether the form was posted via AJAX from the back-end by looking for the
X-Requested-With
header, which should have a value ofXMLHttpRequest
— if that isn't there, then the iframe is asking for the response and you need to send text or HTML. You may want to stringify a JSON response that exposes the values you wanted to feed back to the user likefileName
,fileSize
&fileType
. I'm hoping you can do this yourself or get a colleague to handle it.Capturing the iframe response
As mentioned, the response handler function will need to be in the global scope for the
onload
attribute to bind to, because of old IE being very quirky. I see you're using jQuery, so if you went down the route of stringifying the server response, you could write this function as follows:function parseIframeResponse(){ var response = $('#fileIframe').contents().find('body').text(); var object = $.parseJSON(response); }
Issues with the iframe
load
event bindingAs mentioned earlier, the iframe load event needs to be bound inline as an attribute of the iframe itself — this is because IE will simply fail to register it otherwise. But this is problematic in and of itself because even an empty iframe (an empty or non-present
src
will default toabout:blank
) fires a load event. To mitigate this you will need to discard anyresponse
that evaluates to an empty string as a false positive, and make sure your back-end responds with some content even if it encounters a fault.Presumably, you would then want to use whatever information is in there to execute some of the code you've currently got in the functions
fileSelected
,uploadProgress
, etc.Hope this helps.
EDIT 1: Out-of-the-box solutions
In hindsight, despite writing this off the back of having developed my own solution to the problem, it could be considered negligent not to mention Fine Uploader, a heavily tested (over 700 closed issues!) and well maintained stand-alone plugin that aims to achieve the best file upload experience possible for IE7 and up. There's also a good selection of back-end server components — including ASP.NET — to parse the upload. You might find it easier to tweak this than roll your own!
EDIT 2: Neglected to mention issues with iframe's
load
event. Amended answer in place.这篇关于创建在IE中工作的文件上传的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- The form now has a