Javascript 通过 AJAX 和 jQuery 使用 HTML5 文件上传
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4006520/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using HTML5 file uploads with AJAX and jQuery
提问by Joshua Cody
Admittedly, there are similar questions lying around on Stack Overflow, but it seems none quite meet my requirements.
诚然,Stack Overflow 上也有类似的问题,但似乎没有一个完全符合我的要求。
Here is what I'm looking to do:
这是我想要做的:
- Upload an entire form of data, one piece of which is a singlefile
- Work with Codeigniter's file upload library
- 上传完整形式的数据,其中一个是单个文件
- 使用 Codeigniter 的文件上传库
Up until here, all is well. The data gets in my database as I need it. But I'd also like to submit my form via an AJAX post:
到这里为止,一切都很好。数据在我需要时进入我的数据库。但我也想通过 AJAX 帖子提交我的表单:
- Using the native HTML5 File API, not flash or an iframe solution
- Preferably interfacing with the low-level
.ajax()
jQuery method
- 使用原生 HTML5 文件 API,而不是 Flash 或 iframe 解决方案
- 最好与低级
.ajax()
jQuery 方法交互
I think I could imagine how to do this by auto-uploading the file when the field's value changes using pure javascript, but I'd rather do it all in one fell swoop on for submit in jQuery. I'm thinking it's not possible to do via query strings as I need to pass the entire file object, but I'm a little lost on what to do at this point.
我想我可以想象如何通过在字段的值更改时使用纯 javascript 自动上传文件来做到这一点,但我宁愿一举完成这一切,以便在 jQuery 中提交。我认为通过查询字符串是不可能的,因为我需要传递整个文件对象,但我对此时要做什么有点迷茫。
Can this be achieved?
这能实现吗?
回答by clarkf
It's not too hard. Firstly, take a look at FileReader Interface.
这不是太难。首先,看看FileReader Interface。
So, when the form is submitted, catch the submission process and
所以,当表单提交时,抓住提交过程并
var file = document.getElementById('fileBox').files[0]; //Files[0] = 1st file
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = shipOff;
//reader.onloadstart = ...
//reader.onprogress = ... <-- Allows you to update a progress bar.
//reader.onabort = ...
//reader.onerror = ...
//reader.onloadend = ...
function shipOff(event) {
var result = event.target.result;
var fileName = document.getElementById('fileBox').files[0].name; //Should be 'picture.jpg'
$.post('/myscript.php', { data: result, name: fileName }, continueSubmission);
}
Then, on the server side (i.e. myscript.php):
然后,在服务器端(即 myscript.php):
$data = $_POST['data'];
$fileName = $_POST['name'];
$serverFile = time().$fileName;
$fp = fopen('/uploads/'.$serverFile,'w'); //Prepends timestamp to prevent overwriting
fwrite($fp, $data);
fclose($fp);
$returnData = array( "serverFile" => $serverFile );
echo json_encode($returnData);
Or something like it. I may be mistaken (and if I am, please, correct me), but this should store the file as something like 1287916771myPicture.jpg
in /uploads/
on your server, and respond with a JSON variable (to a continueSubmission()
function) containing the fileName on the server.
或者类似的东西。我可能是错误的(如果我是,请指正),但这应该在文件存储的东西就像1287916771myPicture.jpg
在/uploads/
你的服务器上,并用JSON变量(一个响应的continueSubmission()
功能)包含服务器上的文件名。
Check out fwrite()
and jQuery.post()
.
On the above page it details how to use readAsBinaryString()
, readAsDataUrl()
, and readAsArrayBuffer()
for your other needs (e.g. images, videos, etc).
在上面的页面上,详细说明了如何使用readAsBinaryString()
、readAsDataUrl()
和readAsArrayBuffer()
满足您的其他需求(例如图像、视频等)。
回答by Gheljenor
With jQuery (and without FormData API) you can use something like this:
使用 jQuery(没有 FormData API)你可以使用这样的东西:
function readFile(file){
var loader = new FileReader();
var def = $.Deferred(), promise = def.promise();
//--- provide classic deferred interface
loader.onload = function (e) { def.resolve(e.target.result); };
loader.onprogress = loader.onloadstart = function (e) { def.notify(e); };
loader.onerror = loader.onabort = function (e) { def.reject(e); };
promise.abort = function () { return loader.abort.apply(loader, arguments); };
loader.readAsBinaryString(file);
return promise;
}
function upload(url, data){
var def = $.Deferred(), promise = def.promise();
var mul = buildMultipart(data);
var req = $.ajax({
url: url,
data: mul.data,
processData: false,
type: "post",
async: true,
contentType: "multipart/form-data; boundary="+mul.bound,
xhr: function() {
var xhr = jQuery.ajaxSettings.xhr();
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(event) {
var percent = 0;
var position = event.loaded || event.position; /*event.position is deprecated*/
var total = event.total;
if (event.lengthComputable) {
percent = Math.ceil(position / total * 100);
def.notify(percent);
}
}, false);
}
return xhr;
}
});
req.done(function(){ def.resolve.apply(def, arguments); })
.fail(function(){ def.reject.apply(def, arguments); });
promise.abort = function(){ return req.abort.apply(req, arguments); }
return promise;
}
var buildMultipart = function(data){
var key, crunks = [], bound = false;
while (!bound) {
bound = $.md5 ? $.md5(new Date().valueOf()) : (new Date().valueOf());
for (key in data) if (~data[key].indexOf(bound)) { bound = false; continue; }
}
for (var key = 0, l = data.length; key < l; key++){
if (typeof(data[key].value) !== "string") {
crunks.push("--"+bound+"\r\n"+
"Content-Disposition: form-data; name=\""+data[key].name+"\"; filename=\""+data[key].value[1]+"\"\r\n"+
"Content-Type: application/octet-stream\r\n"+
"Content-Transfer-Encoding: binary\r\n\r\n"+
data[key].value[0]);
}else{
crunks.push("--"+bound+"\r\n"+
"Content-Disposition: form-data; name=\""+data[key].name+"\"\r\n\r\n"+
data[key].value);
}
}
return {
bound: bound,
data: crunks.join("\r\n")+"\r\n--"+bound+"--"
};
};
//----------
//---------- On submit form:
var form = $("form");
var $file = form.find("#file");
readFile($file[0].files[0]).done(function(fileData){
var formData = form.find(":input:not('#file')").serializeArray();
formData.file = [fileData, $file[0].files[0].name];
upload(form.attr("action"), formData).done(function(){ alert("successfully uploaded!"); });
});
With FormData API you just have to add all fields of your form to FormData object and send it via $.ajax({ url: url, data: formData, processData: false, contentType: false, type:"POST"})
使用 FormData API,您只需将表单的所有字段添加到 FormData 对象并通过 $.ajax({ url: url, data: formData, processData: false, contentType: false, type:"POST"}) 发送