常规实现方法:
ajax无法实现上传文件,因此常规情况下,要实现无刷新上传文件的做法,是在页面隐藏一个iframe,然后将上传form的target指向这个iframe,变相的实现。如下代码:
1
2
3
4
5
6
7
|
<
p
id
=
"uploading"
style
=
"display:none;"
>Uploading...<
img
src
=
"loading.gif"
/>
<
form
action
=
"upload.php"
method
=
"post"
enctype
=
"multipart/form-data"
target
=
"upload_target"
onsubmit
=
"startUpload();"
>
File: <
input
name
=
"myfile"
type
=
"file"
/>
<
input
type
=
"submit"
name
=
"submitBtn"
value
=
"Upload"
/>
</
form
>
<
iframe
id
=
"upload_target"
name
=
"upload_target"
src
=
"#"
style
=
";height:0;border:0px solid #fff;"
>
</
iframe
>
|
upload_target是一个长宽都是0的iframe,所以页面上看不见他。还需要配合js,使得效果更好:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<script>
function
startUpload(){
$(
'#uploading'
).show();
}
function
finisheUpload(i){
$(
'#uploading'
).hide();
if
(i==
0
)
{
alert(
"上传成功"
);
}
else
{
alert(
"上传失败"
);
}
}
</script>
|
其中startUpload方法是在提交表单的时候触发,而由于没有什么回调函数,因此finisheUpload只能由upload.php文件的输出控制。通常就是在输出中输出一段javascript代码来执行。
php代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
header(
"Content-Type:text/html;charset=utf-8"
);
$destination_path
=
getcwd
().DIRECTORY_SEPARATOR;
$filname
=
$destination_path
.
basename
(
$_FILES
[
'myfile'
][
'name'
]);
$filname
=iconv(
"UTF-8"
,
"gb2312"
,
$filname
);
if
(move_uploaded_file(
$_FILES
[
'myfile'
][
'tmp_name'
],
$filname
)) {
echo
"<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(0);</script> "
;
}
else
{
echo
"<script language=\"javascript\" type=\"text/javascript\">window.parent.finisheUpload(1);</script> "
;
}
|
注意,输出javascript的时候,由于调用的js方法是在iframe外定义的,要在iframe内调用js方法,需要指定window.parent。
————————
HTML5下的实现方法:
先介绍一下FileReader对象:
FileReader对象的详细说明可以在W3C官方文档中查看。
该接口提供方法来读取文件对象或者Blob对象。它继承了EventTarget,接口的描述如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[Constructor]
interface
FileReader: EventTarget {
// async read methods
void
readAsArrayBuffer(Blob blob);
void
readAsText(Blob blob, optional DOMString label);
void
readAsDataURL(Blob blob);
void
abort();
// states
const
unsigned
short
EMPTY =
0
;
const
unsigned
short
LOADING =
1
;
const
unsigned
short
DONE =
2
;
readonly attribute unsigned
short
readyState;
// File or Blob data
readonly attribute (DOMString or ArrayBuffer)? result;
readonly attribute DOMError? error;
// event handler attributes
attribute EventHandler attribute EventHandler onprogress;
attribute EventHandler attribute EventHandler onabort;
attribute EventHandler onerror;
attribute EventHandler };
|
可以看到有4个异步方法,其中3个是读取,1个是放弃,4个状态属性,1个result,1个error和6个事件。(之前还有readAsBinaryString方法,不过已经被W3C去除了)这6个事件的触发时机如下:
loadstart --When the read starts.
progress --While reading (and decoding) blob
abort --When the read has been aborted. For instance, by invoking the abort() method.
error --When the read has failed (see errors).
load --When the read has successfully completed.
loadend --When the request has completed (either in success or failure).
下面演示一个例子,读取一个文本文档,并且alert出来内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<script>
function
readfile(dom)
{
var
file = dom.files[0];
var
textType = /text.*/;
//正则表达式,使之匹配text/html,text/plain
if
(file.type.match(textType)) {
var
reader =
new
FileReader();
//注册事件函数,即等读完内容后,要做的事情
reader.onload =
function
(e) {
alert(reader.result);
}
//异步读取内容
reader.readAsText(file,
'gb2312'
);
$(
"#msg"
).html(
"正在执行异步读取"
);
}
else
{
alert(
"文件不支持"
);
}
}
</script>
<input type=
"file"
id=
"testfiles"
name=
"files[]"
onchange=
"readfile(this);"
/>
<div id=
"msg"
></div>
|
——————————————————————————————
下面演示一个例子,读取一个DataURL的,DataURL其实是一种DataURI(要知道URI的更多细节,可以去http://css-tricks.com/data-uris/,或者维基百科了解更多)。它提供了一种在浏览器中显示数据的途径。比如你要显示一个图片(百度的logo)的话,你可以如下写:
1
|
<
img
src
=
"http://www.baidu.com/img/bdlogo.gif"
/>
|
你也可以用它的URI去写,如下:
<img src="data:image/gif;base64,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" />
src中填写的字符串就是DataURI,格式如下:
data:[<mime type>][;charset=<charset>][;base64],<encoded data>
这种URI其实很有用的,可以减少HTTP请求,使得网站提速。因此获取了URI的话就可以加载本地的图像了。示例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<script>
function
loadimg(dom)
{
var
file = dom.files[0];
//正则表达式,使之匹配image/jpeg等
var
imageType = /image.*/;
if
(file.type.match(imageType)) {
var
reader =
new
FileReader();
reader.onload =
function
(e) {
var
img =
new
Image();
img.src = reader.result;
$(
"#divimg"
).append(img);
}
reader.readAsDataURL(file);
}
else
{
alert(
"文件不支持"
);
}
}
</script>
<input type=
"file"
id=
"testfiles"
name=
"files[]"
onchange=
"loadimg(this);"
/>
<div id=
"divimg"
></div>
|
————————————————————————————————————
还有一个方法是readAsArrayBuffer,从字面就可以看出,是把文件读取到一个数组缓冲区。
使用readAsArrayBuffer这种方法实现上传文件
下面演示一个例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<script>
function
upload()
{
var
file = $(
'#testfiles'
)[0].files[0];
var
reader =
new
FileReader();
reader.onload =
function
(rResult) {
var
filename = file.name;
var
options = {
type:
'POST'
,
url:
'upload.php?filename='
+filename,
data: reader.result,
success:
function
(result){
alert(result.msg);
},
processData:
false
,
// 告诉jQuery不要去处理发送的数据
contentType:
false
,
// 告诉jQuery不要去设置Content-Type请求头
dataType:
"json"
};
$.ajax(options);
};
reader.readAsArrayBuffer(file);
}
</script>
<input type=
"button"
value=
"upload"
onclick=
"javascript:upload();"
/>
|
后端PHP代码:
1
2
3
4
5
6
7
8
9
10
|
try
{
$filename
=
$_GET
[
'filename'
];
$input
=
file_get_contents
(
"php://input"
); //这个是获取请求的InputStream,PHP下的写法
file_put_contents
(
$filename
,
$input
);
//保存成文件。
echo
json_encode(
array
(
"msg"
=>
"上传成功"
));
}
catch
(Exception
$e
)
{
echo
json_encode(
array
(
"msg"
=>
"上传失败"
));
}
|
FormData方法
FromData的官方说明在这里。利用FormData
对象,你可以使用一系列的键值对来模拟一个完整的表单。
以下给出一个例子,允许上传多个文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<script>
function
upload()
{
var
formdata =
new
FormData();
$.each($(
'#testfiles'
)[0].files,
function
(i, file) {
formdata.append(
'file-'
+i, file);
});
var
options = {
type:
'POST'
,
url:
'upload.php'
,
data: formdata,
success:
function
(result){
alert(result.msg);
},
processData:
false
,
// 告诉jQuery不要去处理发送的数据
contentType:
false
,
// 告诉jQuery不要去设置Content-Type请求头
dataType:
"json"
};
$.ajax(options);
}
</script>
<input type=
"button"
value=
"upload"
onclick=
"javascript:upload();"
/>
|
后台PHP代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
try
{
foreach
(
$_FILES
as
$key
=>
$value
)
{
//print_r ($_FILES[$key]); echo "<br>";
move_uploaded_file(
$value
[
"tmp_name"
],
$value
[
'name'
]);
}
echo
json_encode(
array
(
"msg"
=>
"上传成功"
));
}
catch
(Exception
$e
)
{
echo
json_encode(
array
(
"msg"
=>
"上传失败"
));
}
|
参考文档:
https://developer.mozilla.org/zh-CN/docs/DOM/XMLHttpRequest/FormData/Using_FormData_Objects
http://dev.w3.org/2006/webapi/FileAPI/#FileReader-interface
http://www.w3.org/TR/XMLHttpRequest2/#interface-formdata
http://blog.teamtreehouse.com/reading-files-using-the-html5-filereader-api
本文转自cnn23711151CTO博客,原文链接:http://blog.51cto.com/cnn237111/1330089,如需转载请自行联系原作者