javascript及php筆記:自己動手寫一個ajax異步上傳文件的jquery插件


  前不久做了一個文件上傳的功能頁面,這次開發中我遇到了些問題,開發的時候由於時間比較緊張,因此有些細節做得並不是太仔細,所以最近幾天將前面做得東西整理了下,在這里和大家 一起分享下。

  首先我介紹下我所做的功能頁面,頁面會同時上傳兩個文件,一個是數據文件,一個是簽名文件,而且數據文件一般都是比較大的,上傳的同時文件的數據要同步解析同步校驗,最終錄入到數據庫里,這就導致文件上傳的時間都比較長,為了得到更好的用戶體驗,上傳文件的時候頁面做一個等待的遮罩效果,這個如果用ajax異步提交就能很好的作出效果,但是標准的ajax技術可以異步上傳文件嗎?答案是不行,至少標准的ajax技術里沒有直接用來上傳文件的方法,這時同事給了我一個項目組里使用過的ajax上傳文件的插件,研究了下很讓我失望,這個插件只能上傳一個文件同時也不支持遮罩的效果,況且代碼也超級爛:作為jQuery插件,代碼里面居然很少使用jQuery方法,也不知道當時同事從那里找到了這個插件。

  我現在對每一次能寫js代碼的機會都堅決把握,這次也不例外,我想自己寫個ajax上傳的jQuery插件。

  ajax上傳文件原理是一種用不可見的form和iframe框架模擬ajax異步提交的方式,我在制作的插件里添加了一個用於上傳文件的form和iframe,其中form也是對用戶不可見的,但是它是負責文件上傳的form,iframe則是接收返回數據的載體,下面我把我頁面的源碼和頁面上傳文件時候的代碼貼在下面,大家可以比較下:

  源文件ajaxuploadfile.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Ajax File Upload PHP</title>
</head>
<script type="text/javascript" src="js/jquery-1.7.1.js"></script>
<script type="text/javascript" src="js/jquery.ajaxupload.1.0.js"></script>
<body>
    <form id="aupfFrm" name="aupfFrm" style="position: absolute;top:50px;left: 80px;">
        <label for="username">&nbsp;&nbsp;&nbsp;用戶姓名:</label>
        <input type="text" id="username" name="username"/>
        <br/>
        <label for="userpwd">&nbsp;&nbsp;&nbsp;用戶密碼:</label>
        <input type="password" id="userpwd" name="userpwd"/>
        <br/>
        <label for="uploadFile">請選擇文件1:</label></label>
        <input type="file" id="uploadFile1" name="uploadFile1"/>
        <br/>
        <label for="uploadFile">請選擇文件2:</label></label>
        <input type="file" id="uploadFile2" name="uploadFile2"/>
        <br/>
        <br/>
        <center>
            <input type="button" id="upBtn" name="upBtn" value="BUTTON"/>
        </center>
    </form>
    <span id="showErrInfo" style="color: red"></span>
</body>
</html>
<script type="text/javascript">
    $(document).ready(function(){
        /*
        $("#upBtn").bind("click",function(){
            $.ajaxFileUpload({
                url:"php/uploadfile.php",
                loadPicUrl:"images/loading.gif",
                formElemIds:["username","userpwd","uploadFile1","uploadFile2"],
                dataType:"html",
                success:function(data){
                    $("body").html(data);
                },
                error:function(data){
                    alert(data);
                }
            });
        });
        */
        $("#upBtn").bind("click",function(){
            $.ajaxFileUpload({
                url:"php/uploadfile.php",
                loadPicUrl:"images/loading.gif",
                formElemIds:["username","userpwd","uploadFile1","uploadFile2"],
                dataType:"json",
                success:function(data){
                    $("#showErrInfo").text("");// 清空原來的提示信息
                    $("#showErrInfo").text("用戶姓名:" + data.username + 
                                                ";用戶密碼:" + data.userpwd + 
                                                        ";請求類型:" + data.dataType + 
                                                            ";提示信息:" + data.retTipInfo);
                },
                error:function(data){
                    alert(data);
                }
            });
        });        
    });
</script>

  上傳文件過程中的頁面代碼:

<form enctype="multipart/form-data" id="jqAjaxUploadFrom1344865748585"
name="jqAjaxUploadFrom1344865748585" method="post" action="php/uploadfile.php"
style="position: absolute; top: -1200px; left: -1200px;" target="jqAjaxUploadIframe1344865748585">
    <input type="text" name="username" id="jqUploadFile1344865748585username">
    <input type="password" name="userpwd" id="jqUploadFile1344865748585userpwd">
    <input type="file" name="uploadFile1" id="jqUploadFile1344865748585uploadFile1">
    <input type="file" name="uploadFile2" id="jqUploadFile1344865748585uploadFile2">
    <input type="hidden" name="dataTp" id="dataTp" value="json">
</form>
<iframe name="jqAjaxUploadIframe1344865748585" id="jqAjaxUploadIframe1344865748585"
style="position: absolute; top: -1000px; left: -1000px;" src="php/uploadfile.php">
</iframe>
<html>
    
    <head>
        <meta content="text/html; charset=UTF-8" http-equiv="Content-Type">
        <title>
            Ajax File Upload PHP
        </title>
        <script src="js/jquery-1.7.1.js" type="text/javascript">
        </script>
        <script src="js/jquery.ajaxupload.1.0.js" type="text/javascript">
        </script>
    </head>
    
    <body>
        <form style="position: absolute;top:50px;left: 80px;" name="aupfFrm" id="aupfFrm">
            <label for="username">
                &nbsp;&nbsp;&nbsp;用戶姓名:
            </label>
            <input type="text" name="username" id="username">
            <br>
            <label for="userpwd">
                &nbsp;&nbsp;&nbsp;用戶密碼:
            </label>
            <input type="password" name="userpwd" id="userpwd">
            <br>
            <label for="uploadFile">
                請選擇文件1:
            </label>
            <input type="file" name="uploadFile1" id="uploadFile1">
            <br>
            <label for="uploadFile">
                請選擇文件2:
            </label>
            <input type="file" name="uploadFile2" id="uploadFile2">
            <br>
            <br>
            <center>
                <input type="button" value="BUTTON" name="upBtn" id="upBtn">
            </center>
        </form>
        <span style="color: red" id="showErrInfo">
        </span>
        <script type="text/javascript">
            $(document).ready(function() {
                /*
        $("#upBtn").bind("click",function(){
            $.ajaxFileUpload({
                url:"php/uploadfile.php",
                loadPicUrl:"images/loading.gif",
                formElemIds:["username","userpwd","uploadFile1","uploadFile2"],
                dataType:"html",
                success:function(data){
                    $("body").html(data);
                },
                error:function(data){
                    alert(data);
                }
            });
        });
        */
                $("#upBtn").bind("click",
                function() {
                    $.ajaxFileUpload({
                        url: "php/uploadfile.php",
                        loadPicUrl: "images/loading.gif",
                        formElemIds: ["username", "userpwd", "uploadFile1", "uploadFile2"],
                        dataType: "json",
                        success: function(data) {
                            $("#showErrInfo").text(""); // 清空原來的提示信息
                            $("#showErrInfo").text("用戶姓名:" + data.username + ";用戶密碼:" + data.userpwd + ";請求類型:" + data.dataType + ";提示信息:" + data.retTipInfo);
                        },
                        error: function(data) {
                            alert(data);
                        }
                    });
                });
            });
        </script>
        <div id="up_overlay" style="display: block; height: 100%; width: 100%; left: 0px; top: 0px; position: fixed; z-index: 999; background-color: rgb(0, 0, 0); opacity: 0.59;">
        </div>
        <img id="loadimg" style="left: 0px; top: 0px; margin-left: 280px; margin-top: 150px; position: fixed; z-index: 999; display: block;"
        src="images/loading.gif">
        <form enctype="multipart/form-data" id="jqAjaxUploadFrom1344865748585"
        name="jqAjaxUploadFrom1344865748585" method="post" action="php/uploadfile.php"
        style="position: absolute; top: -1200px; left: -1200px;" target="jqAjaxUploadIframe1344865748585">
            <input type="text" name="username" id="jqUploadFile1344865748585username">
            <input type="password" name="userpwd" id="jqUploadFile1344865748585userpwd">
            <input type="file" name="uploadFile1" id="jqUploadFile1344865748585uploadFile1">
            <input type="file" name="uploadFile2" id="jqUploadFile1344865748585uploadFile2">
            <input type="hidden" name="dataTp" id="dataTp" value="json">
        </form>
        <iframe name="jqAjaxUploadIframe1344865748585" id="jqAjaxUploadIframe1344865748585"
        style="position: absolute; top: -1000px; left: -1000px;" src="php/uploadfile.php">
        </iframe>
    </body>

</html>

  其中form代碼:

        <form enctype="multipart/form-data" id="jqAjaxUploadFrom1344865748585"
        name="jqAjaxUploadFrom1344865748585" method="post" action="php/uploadfile.php"
        style="position: absolute; top: -1200px; left: -1200px;" target="jqAjaxUploadIframe1344865748585">
            <input type="text" name="username" id="jqUploadFile1344865748585username">
            <input type="password" name="userpwd" id="jqUploadFile1344865748585userpwd">
            <input type="file" name="uploadFile1" id="jqUploadFile1344865748585uploadFile1">
            <input type="file" name="uploadFile2" id="jqUploadFile1344865748585uploadFile2">
            <input type="hidden" name="dataTp" id="dataTp" value="json">
        </form>

  iframe代碼:

        <iframe name="jqAjaxUploadIframe1344865748585" id="jqAjaxUploadIframe1344865748585"
        style="position: absolute; top: -1000px; left: -1000px;" src="php/uploadfile.php">
        </iframe>

  遮罩的代碼:

        <div id="up_overlay" style="display: block; height: 100%; width: 100%; left: 0px; top: 0px; position: fixed; z-index: 999; background-color: rgb(0, 0, 0); opacity: 0.59;">
        </div>
        <img id="loadimg" style="left: 0px; top: 0px; margin-left: 280px; margin-top: 150px; position: fixed; z-index: 999; display: block;"
        src="images/loading.gif">

  調用方式:

        $("#upBtn").bind("click",function(){
            $.ajaxFileUpload({
                url:"php/uploadfile.php",
                loadPicUrl:"images/loading.gif",
                formElemIds:["username","userpwd","uploadFile1","uploadFile2"],
                dataType:"json",
                success:function(data){
                    $("#showErrInfo").text("");// 清空原來的提示信息
                    $("#showErrInfo").text("用戶姓名:" + data.username + 
                                                ";用戶密碼:" + data.userpwd + 
                                                        ";請求類型:" + data.dataType + 
                                                            ";提示信息:" + data.retTipInfo);
                },
                error:function(data){
                    alert(data);
                }
            });
        });    

  

參數介紹:
url:請求路徑;
loadPicUrl:遮罩效果的等待圖片;
formElemIds:提交到服務端的form元素的id值,注意一定要是個數組,如果那個字段的id沒有寫到數組里,那么它的數據也不會提交到服務端;
dataType:指定返回值的數據類型,我計划寫html,json,xml和script,現在實現了html和script,其他兩種也很簡單,以后有空再補充;
success:文件上傳成功的回調函數;
error:文件上傳失敗的回調函數。

 

下面就是我程序的源碼了:

首先還是目錄結果,如圖:

javascript代碼(jquery.ajaxupload.1.0.js):

View Code
// 制作jQuery插件 author:xiajun  add 2012-08-13 ajax多文件上傳
;(function($){
    $.extend({
        createUploadIframe:function(id,url){// 創建用於文件上傳的iframe
            var upIframeId = "jqAjaxUploadIframe" + id;
            var jqIfrmObj = $('<iframe id="' + upIframeId + '" name="' + upIframeId + '" />');
            
            // iframe的位置
            jqIfrmObj.css('position','absolute');
            jqIfrmObj.css('top','-1000px');
            jqIfrmObj.css('left','-1000px');
            jqIfrmObj.attr('src',url);
            
            $('body').append(jqIfrmObj);
            return jqIfrmObj;
        },
        createUploadForm:function(timeId,fileElems,dataType){// 創建用於上傳文件的form
            var upFormId = "jqAjaxUploadFrom" + timeId;
            var jqFormObj = $('<form  action="" method="POST" name="' + upFormId + '" id="' + upFormId + '" enctype="multipart/form-data"></form>');
            
            for (var i = 0,len = fileElems.length;i < len;i++){
                var fileElemObj = fileElems[i],
                    fileId = 'jqUploadFile' + timeId + fileElemObj,
                    oldElem = $('#' + fileElemObj),
                    newElem = $(oldElem).clone();
                    
                $(oldElem).attr('id',fileId);
                $(oldElem).before(newElem);
                $(oldElem).appendTo(jqFormObj);
            }
            
            // 數據返回類型
            var dataTpIpt = $("<input type='hidden' id='dataTp' name = 'dataTp'/>");
            dataTpIpt.val(dataType);
            jqFormObj.append(dataTpIpt);
            
            $(jqFormObj).css('position', 'absolute');
            $(jqFormObj).css('top', '-1200px');
            $(jqFormObj).css('left', '-1200px');
            $(jqFormObj).appendTo('body');    
            
            return jqFormObj;        
        },
        createOverLay:function(){// 創建遮罩效果 
            var overLayDiv = $("<div></div>");
            overLayDiv.attr("id","up_overlay");
            overLayDiv.css("display","block");
            overLayDiv.css("height","100%");
            overLayDiv.css("width","100%");
            overLayDiv.css("left","0px");
            overLayDiv.css("top","0px");
            overLayDiv.css("position","fixed");
            overLayDiv.css("z-index","999");
            overLayDiv.css("background-color","#000000");
            overLayDiv.css("opacity","0.59");
            overLayDiv.css("filter","Alpha(opacity=50)");
            $("body").append(overLayDiv);
        },
        createLoadingPic:function(loadPicUrl){// 創建正在加載的圖片
            var oLoadingPic = $("<img></img>");
            oLoadingPic.attr("id","loadimg");
            oLoadingPic.css("left","0px");
            oLoadingPic.css("top","0px");
            oLoadingPic.css("margin-left","280px");
            oLoadingPic.css("margin-top","150px");
            oLoadingPic.css("position","fixed");
            oLoadingPic.css("z-index","999");
            oLoadingPic.css("display","block");
            
            oLoadingPic.attr("src",loadPicUrl);
            
            $("body").append(oLoadingPic);
        },
        ajaxFileUpload:function(oJson){// 文件上傳方法
            // 遮罩效果 start
            jQuery.createOverLay();
            jQuery.createLoadingPic(oJson.loadPicUrl);
            // 遮罩效果 end
            
            // 創建用於上傳文件的iframe和form start
            var timeId = new Date().getTime();
            var upfForm = jQuery.createUploadForm(timeId,oJson.formElemIds,oJson.dataType);
                upfIframe = jQuery.createUploadIframe(timeId,oJson.url),
                upfFormId = "jqAjaxUploadFrom" + timeId,
                upfIframeId = "jqAjaxUploadIframe" + timeId;
            // 創建用於上傳文件的iframe和form end
                
            // 上傳文件的回調函數 start
            var xml = {};
            var uploadFileCallback = function(){
                var cbUpfIfrm = $("#" + upfIframeId);
                try{
                    xml = cbUpfIfrm.contents().find("body");
                    
                    var sErrFlag = $.trim(cbUpfIfrm.contents().find("body").find("input[id='errFlag']").val()),
                        sTipInfo = $.trim(cbUpfIfrm.contents().find("body").find("input[id='errInfo']").val());
                    
                    if (sErrFlag == 'false'){
                        if (oJson.error){
                            oJson.error(sTipInfo);    
                        }
                    }else if (sErrFlag == 'true'){
                        var retData = jQuery.uploadRetHttpData(xml,oJson.dataType);
                        
                        if (oJson.success){
                            $("#up_overlay").remove();
                            $("#loadimg").remove();
                            oJson.success(retData);    
                        }                        
                    }
                    
                    $(cbUpfIfrm).unbind();
                    
                    setTimeout(function(){
                        $(upfIframe).remove();
                        $(upfForm).remove();
                    },100);                    
                            
                    xml = null;        
                }catch(e){
                    alert("Callback error1:" + e);    
                }

            }
            // 上傳文件的回調函數 end
            
            try{
                var ajaxUpfForm = $("#" + upfFormId);
                ajaxUpfForm.attr("action",oJson.url);
                ajaxUpfForm.attr("method","post");
                ajaxUpfForm.attr("target",upfIframeId);
                
                if (ajaxUpfForm.attr("encoding")){
                    ajaxUpfForm.attr("encoding","multipart/form-data");
                }else{
                    ajaxUpfForm.attr("enctype","multipart/form-data");    
                }
                
                ajaxUpfForm.submit();
            }catch(e){
                alert("ajaxFileUpload Error:" + e);
            }
            
            $("#" + upfIframeId).bind("load",uploadFileCallback);
            
            return {abort: function () {}};    
        },
        uploadRetHttpData:function(resp,type){// 上傳返回的數據
            switch (type) {
                case 'html':
                    return resp.find("div[id='resultData']").html();
                    break;
                case 'xml':
                    alert("to do ....");// 以后再寫
                    break;
                case 'json':
                    return eval("(" + resp.find("div[id='resultData']").text() + ")");
                    break;
                case 'script':
                    alert("to do ....");// 以后再寫
                    break;
                default:
                    break;
            }
        }
    });
})(jQuery);

  服務端我使用的是php,我的工作語言是java,今天使用php也是第一次嘗試另一種服務端語言,這個決定也不是臨時的,我打算以后自我學習所寫的代碼都將會是腳本語言,最近一段時間是php,等php熟練后就是python,我的計划是學會四門腳本語言,另外兩種是nodeJs和ruby了。

  使用php寫代碼的感覺就是爽,比java方便多了,做網站就應該用php這樣的腳本語言。

下面是我服務端源碼(uploadfile.php):

<?php
    //sleep(234);
    
    /**
     * 上傳錯誤處理函數
     * Enter description here ...
     * @param $errCode
     */
    function parseFileErr($fileNm,$errCode){
        setOperateFlag('false');
        switch ($errCode) {
            case 1:
                echo $fileNm . ":文件大小超過了PHP.ini中的文件限制!";
                break;
            case 2:
                echo $fileNm . ":文件大小超過了瀏覽器限制!";
                break;
            case 3:
                echo $fileNm . ":文件部分被上傳!";
                break;
            case 4:
                echo $fileNm . ":沒有找到要上傳的文件!";
                break;
            case 5:
                echo $fileNm . ":服務器臨時文件夾丟失,請重新上傳!";
                break;
            case 6:
                echo $fileNm . ":文件寫入到臨時文件夾出錯!";
                break;            
            default:
                echo $fileNm . ":文件上傳錯誤!!";
                break;
        }
    }
    
    /**
     * 設置操作狀態 true表示成功 false 表示失敗
     * Enter description here ...
     * @param $flag
     */
    function setOperateFlag($flag,$tipInfo){
        echo "<input type='hidden' id='errFlag' name='errFlag' value='" . $flag . "' />";
        echo "<input type='hidden' id='errInfo' name='errInfo' value='" . $tipInfo . "' />";
    }
    
    /**
     * 校驗文件的類型和大小
     * Enter description here ...
     * @param $upFileTp
     * @param $upFileSize
     */
    function checkFileTypeAndSize($upFileTp,$upFileSize){
        if ($upFileSize < 28480){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * 判斷上傳文件是否存在
     * Enter description here ...
     * @param $upFileNm
     */
    function checkFileExists($upFileNm){
        if (file_exists($upFileNm)){
            return "tp0_" . $upFileNm;// 已存在文件改名字保存
        }else{
            return $upFileNm;
        }
    }
    
    /**
     * 返回數據
     * Enter description here ...
     */
    function resultDataFtn(){
        $reqUserNm = $_REQUEST["username"];
        $reqUserPwd = $_REQUEST["userpwd"];
        $reqDataTp = $_REQUEST["dataTp"];
        echo "<div id='resultData'>";
        if ($reqDataTp == 'html'){
            echo "<h1 style='color:red'>PHP Ajax 多文件上傳 成功</h1>";
        }elseif ($reqDataTp == 'json'){
            $jsonArr = array("username"=> $reqUserNm,
                             "userpwd" => $reqUserPwd,
                             "dataType" => $reqDataTp,
                             "retTipInfo" => "PHP Ajax 多文件上傳 成功");
            echo json_encode($jsonArr);
        }
        echo "</div>";
    }
    
    // 上傳文件1
    $upFile01Name = $_FILES['uploadFile1']['name'];
    $upFile01Size = $_FILES['uploadFile1']['size'];
    $upFile01TmpNm = $_FILES['uploadFile1']['tmp_name'];
    $upFile01Type = $_FILES['uploadFile1']['type'];
    $upFile01Err = $_FILES['uploadFile1']['error'];
    
    // 上傳文件2
    $upFile02Name = $_FILES['uploadFile2']['name'];
    $upFile02Size = $_FILES['uploadFile2']['size'];
    $upFile02TmpNm = $_FILES['uploadFile2']['tmp_name'];
    $upFile02Type = $_FILES['uploadFile2']['type'];    
    $upFile02Err = $_FILES['uploadFile2']['error'];
    
    if ($upFile01Name == '' || $upFile02Name == ''){
        setOperateFlag('false',"請上傳文件!");
        //echo "<script>alert('請上傳文件!');</script>";
    }else{
        if ($upFile01Err > 0 || $upFile02Err > 0){
            //$upFile01Err > 0 ? parseFileErr($upFile01Name, $upFile01Err) : "";
            //$upFile02Err > 0 ? parseFileErr($upFile02Name, $upFile02Err) : "";
            setOperateFlag('false',"上傳失敗!");
        }else{
            if (!checkFileTypeAndSize($upFile01Type, $upFile01Size) || !checkFileTypeAndSize($upFile02Type, $upFile02Size)){    
                setOperateFlag('false','上傳的文件過大!');
                //echo "<script>alert('上傳的文件過大!');</script>";
            }else{
                setOperateFlag('true',"成功");
                move_uploaded_file($upFile01TmpNm, checkFileExists($upFile01Name));
                move_uploaded_file($upFile02TmpNm, checkFileExists($upFile02Name));
                resultDataFtn();// 結果數據處理
            }
        }
    }
?>

  這個插件寫的很匆忙,問題肯定很多,特別是服務端和客戶端有些邏輯有一定耦合,我估計某些童鞋想把插件遷移到其他的服務端上會有點麻煩,等有時間我會進一步改進自己的代碼。

 

  源代碼下載路徑:
  http://files.cnblogs.com/sharpxiajun/ajaxfileupload1.0.zip

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM