【javascript】腳本操作HTTP請求技術Ajax-3 (單個文件上傳)

最近在看《javascript權威指南》的時候,發現它在Ajax技術上講解了關於javascript上傳文件的內容。這也是博主在多年前的一個困擾,曾經解決的辦法就是借用別人的js控件,因此對這個技術理解甚少。當然,解決異步文件上傳的方式有許多種,比如利用flash插件,或者是嵌入iframe元素,等等。接下來就開始介紹我們如何通過Ajax技術進行文件上傳。


首先,支持文件上傳的瀏覽器是有所限制的。其關鍵在於瀏覽器是否支持XMLHttpRequest level 2 的 API,在這裏會有一些對象需要介紹一下。

  1.  File對象, 這個對象不能通過構造函數生成,只能從 input file 控件的 files[]列表獲取.
  2.  FormData對象,這個對象就是form表單的載體。

接下來我們先製作一個簡單的html頁面,其中有兩個關鍵元素

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>文件上傳</title>
    <script type="text/javascript" src="/js/ajax.js"></script>
</head>
<body>

<input type="file" name="file" id="file" />
<button id="go">提交</button>

</body>
</html>

然後我們發現,該頁面存在一個ajax.js腳本. 這個腳本主要就是爲我們提供一些ajax的方法

function  createXHR(){

    if( typeof  XMLHttpRequest != "undefined"){
        return  new XMLHttpRequest();
    }
    if(typeof ActiveXobject == "undefined"){
        throw new Error(" not support ");
    }
    //判斷是否爲 IE
    if(typeof arguments.callee.activeString != "string"){
        var versions = ["MSXML2.XMLHttp.6.0","MSXML2.XMLHttp3.0","MSXML2.XMLHttp"],
            i,len;

        for (var i = 0;i<versions.length;i++) {
            try{
                    new ActiveXobject(versions[i]);
                    arguments.callee.activeString=versions[i];
                    break;
            }catch(ex){
                //  no action
            }
        };
    }
    return  new ActiveXobject(arguments.callee.activeString);
}
/**
*文件表單上傳
*
*@param  {String}    url
*@param  {FormData}  form
*@param  {Function}  callback
*/
function formData(url,form,callback){

    var xhr = createXHR();
    xhr.open("POST",url);
    xhr.onreadystatechange = function(){
        if(xhr.readyState == 4 && (xhr.status == 200)){
            callback(xhr);
        }
    }
    xhr.send(form);
}

只憑這些是不能完成文件上傳的.我們在html頁面中添加一些腳本代碼,最好是在body元素的後部添加script腳本.

function $(id){return document.getElementById(id);} //簡化通過id獲取元素節點

var filedata =[];//生成一個空數組

// 爲file控件添加一個change事件
$("file").addEventListener("change",function(e){
var file = this.files[0]; //默認獲取第一個文件  返回的是一個File對象
//讀取文件的基本屬性
var data =  { name : file.name,  //文件的名稱
              size : file.size,  //文件的大小
              type : file.type || "",  //文件的類型 如果沒有文件類型則爲空
              id   : (file.lastModifiedDate + "").replace(/\W/g, '') + this.size + this.type.replace(/\W/g, '')  //生成文件唯一id
               };
// 將文件名的id存入數組filedata中
filedata.push(data.id);
// 擴展filedata數組,通過文件唯一id 保存文件的基本信息 以及 File文件對象
filedata[data.id] = {info:data,file:file};
console.log(filedata);
},false);
//爲按鈕添加一個click事件
$("go").addEventListener("click",function(){
//判斷等待上傳的文件列表是否爲 0
if(filedata.length <= 0 ){
    alert('請選擇至少一個文件');
    return;
}
var id   = filedata[0];
var data = filedata[id];
// form表單對象
var form = new FormData();
// 請求url地址
var url  ="http://localhost/demo/uploadFile";
// 添加若干參數 第一個參數爲參數名,第二個參數爲參數值
form.append("name",data.info.name);
form.append("type",data.info.type);
form.append("fileid",id);
// 添加文件對象,將文件以字節流的方式作爲請求主體.
form.append("file",data.file);

//調用寫好的函數
formData(url,form,function(res){
    //請求-響應成功
    //刪除上傳成功的文件對象
    delete filedata[id];
    filedata.shift();

    console.log(res.responseText);
});
},false);
//判斷瀏覽器是否支持腳本上傳功能
if(FormData == undefined){
    throw new Error("瀏覽器不支持");
}

這裏並沒有做一些比較好看的css效果,這樣是爲了簡化過程.我們只要看到結果就可以了.寫完了前端的代碼.我們該考慮後端如何寫.

首先我們得確認後端的配置是否允許文件上傳的功能,我的服務端代碼是用PHP寫的,所有要修改一下php.ini 的一些配置,至於如何修改可以查看網絡的資源,搜索關鍵字: php 文件上傳 配置修改.

在確保這些都沒有問題的情況下,我來給大家展示php的端代碼.

<?php
$filename = $_POST['name'];
$fileId   = $_POST['fileid'];
$postfix  = explode(".",$filename); //獲取後綴
$postfix  = empty($postfix[1])?"":".".$postfix[1];

// public_path() 返回的是一個絕對的路徑 可自己定義
$filepath = public_path().'/uploads/'.$fileId.$postfix;
//文件寫入
file_put_contents($filepath, file_get_contents($_FILES["file"]["tmp_name"]), FILE_APPEND);

echo json_encode(array("rs"=>"success","path"=>"/uploads/".$fileId.$postfix));
exit;
?>

下面是測試截圖- Firefox 瀏覽器

我們選擇一個文件後,會觸發 file元素的onchange事件

上面是 filedata 的一些屬性值。

然後我們點擊按鈕上傳後,查看一下我們的請求響應頭部

這個請求頭部類型爲我們的FormData對象自己創建的,切不可自己修改.

這樣我們檢測一下目標路徑.

發現圖片確實已經上傳成功。因此,簡單的異步上傳文件的例子就說到這裏,我們可以發現,還可以進一步完善這個例子,例如添加一個進度監聽事件,查看文件目前上傳的大小情況以及終止或暫停文件上傳等等。要豐富這個功能的話,確實需要點能力。不過,我會慢慢的學習並且做一些案例來講解。

最後給大家推薦一個百度團隊開發的文件上傳組件。點擊打開鏈接


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章