版权声明: 本文由 一只博客 发表于 bloghome博客

文章链接: https://www.bloghome.com.cn/user/cnn237111

常规实现方法:

ajax无法实现上传文件,因此常规情况下,要实现无刷新上传文件的做法,是在页面隐藏一个iframe,然后将上传form的target指向这个iframe,变相的实现。如下代码:

<p id="uploading" >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="#" ></iframe>

upload_target是一个长宽都是0的iframe,所以页面上看不见他。还需要配合js,使得效果更好:

<script>function startUpload(){   $('#uploading').show();}function finisheUpload(i){   $('#uploading').hide();   if(i==0)   {     alert("上传成功");    }    else   {      alert("上传失败");    }}</script>

其中startUpload方法是在提交表单的时候触发,而由于没有什么回调函数,因此finisheUpload只能由upload.php文件的输出控制。通常就是在输出中输出一段javascript代码来执行。

php代码如下:

<?phpheader("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,接口的描述如下:

[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出来内容。

<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)的话,你可以如下写:

<img src="https://cache.yisu.com/upload/information/20200302/42/7387.jpg" />

你也可以用它的URI去写,如下:

<img src="data:p_w_picpath/gif;base64,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" />

src中填写的字符串就是DataURI,格式如下:

data:[<mime type>][;charset=<charset>][;base64],<encoded data>

这种URI其实很有用的,可以减少HTTP请求,使得网站提速。因此获取了URI的话就可以加载本地的图像了。示例代码如下:

<script>function loadimg(dom){    var file = dom.files[0];    //正则表达式,使之匹配p_w_picpath/jpeg等    var p_w_picpathType = /p_w_picpath.*/;    if (file.type.match(p_w_picpathType)) {        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这种方法实现上传文件

下面演示一个例子:

<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代码:

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对象,你可以使用一系列的键值对来模拟一个完整的表单。

以下给出一个例子,允许上传多个文件:

<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代码:

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

http://www.dotblogs.com.tw/junegoat/archive/2013/05/27/test-fileapi-multiupload-readasarraybuffer.aspx