在web瀏覽器上傳文件通常有如下幾種方式:javascript
其中form提交數據以後會整個刷新頁面;
js經過ajax上傳文件雖然不會刷新整個頁面,可是他們都是經過使用formdata對象實現的,formdata對象在老版本的瀏覽器中並不支持;
爲了兼容老版本瀏覽器,使用iframe方式提交;html
下面幾節就分別就這幾種方式實現上傳文件來舉例說明。前端
這是最原始的一種方式,最開始學習web的時候就是使用這種方式提交。
注意:在form表單中若是要上傳文件,必定要設置這個參數: enctype=」multipart/form-data」表示封裝數據類型,把數據分紅一個一個小段傳輸。java
html代碼:python
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .show-img{ display: inline-block; width: 200px; height:200px; } </style> </head> <body> <h1>form表單上傳文件</h1><hr> <form action="/test/" method="POST" enctype="multipart/form-data"> <p>名稱:<input type="text" name="user"></p> <p>文件:<input type="file" name="testfile"></p> <p><input type="submit" value="提交"></p> </form> {% for i in imglist %} <img class="show-img" src="/{{ i.0 }}"> {% endfor %} </body> </html>
在後端要注意上傳過來的文件是經過req.FILES.get() 方法接收的。
後端代碼:jquery
def test(req): if req.method=="GET": imglist=models.Img.objects.all().values_list("img_path") return render(req,"test.html",{"imglist":imglist}) elif req.method=="POST": user=req.POST.get("user") file=req.FILES.get("testfile") path=os.path.join("static","imgs",file.name) with open(path,"wb") as f: for chunk in file.chunks(): f.write(chunk) print(user,file.name,file.size) models.Img.objects.create(img_path=path) return redirect("/test/")
js源碼:web
document.getElementById("js_post").onclick=function(){ var xml=new XMLHttpRequest(); var data=new FormData; //建立formdata對象 data.append("testfile",document.getElementById("file_upload").files[0]);//找到對象以後的file[0]對應的就是文件對象 xml.open("POST","/test/",true); xml.onreadystatechange=function(){ if(xml.readyState==4 && xml.status==200){ //判斷狀態到4了而且返回狀態碼是200時才作操做 var rsp_data=JSON.parse(xml.responseText); //反序列化 if (rsp_data.state){ var url="/"+rsp_data.data; //拼接路徑 var obj=document.createElement("img"); //建立標籤 obj.className="show-img"; //給標籤加樣式 obj.src=url; //給標籤加url document.getElementById("imgs").appendChild(obj); } } }; xml.send(data) } `
html源碼:ajax
<hr><h1>ajax上傳文件</h1><hr> <p>文件:<input id="file_upload" type="file" name="testfile"></p> <p><button id="js_post">原生js提交</button> <button id="jquery_post">jquery提交</button></p> <div id="imgs"> {% for i in imglist %} <img class="show-img" src="/{{ i.0 }}"> {% endfor %} </div>
後端源碼:json
def test(req): if req.method=="GET": imglist=models.Img.objects.all().values_list("img_path") return render(req,"test.html",{"imglist":imglist}) elif req.method=="POST": user=req.POST.get("user",None) file=req.FILES.get("testfile") path=os.path.join("static","imgs",file.name) with open(path,"wb") as f: for chunk in file.chunks(): f.write(chunk) print(user,file.name,file.size) models.Img.objects.create(img_path=path) # return redirect("/test/") msg={"code":200,"state":True,"data":path} return HttpResponse(json.dumps(msg))
注意:FormData對象在添加文件對象的時候並非把標籤直接給append進去,而是找到標籤以後.file(0)纔是文件對象後端
這裏的html代碼和後端代碼相對上面沒有改變,這裏就不列出來了。
jquery代碼:
$("#jquery_post").on("click",function(){ var data=new FormData; data.append("testfile",document.getElementById("file_upload").files[0]); $.ajax({ url:"/test/", type:"POST", dataType:"JSON", data:data, contentType: false, processData: false, success:function(rst){ if(rst.state){ var url="/"+rst.data; $('<img class="show-img" src="'+url+'">').appendTo("#imgs") } } }) })
注意:jquery的ajax會自動把咱們的數據轉換成字符串,不想轉換時須要在ajax裏面寫入:contentType: false,processData: false,
html代碼:
<hr><h1>form+iframe上傳文件</h1><hr> <p><iframe id="uploadfile" name="uploadfile" style="display: none"></iframe></p> <!--注意這裏的name要和form中的target一致--> <form target="uploadfile" action="/test/" method="POST" enctype="multipart/form-data"> <p>名稱:<input type="text" name="user"></p> <p>文件:<input type="file" name="testfile"></p> <p><input type="submit" value="提交"></p> </form> <div id="imgs"> {% for i in imglist %} <img class="show-img" src="/{{ i.0 }}"> {% endfor %} </div>
注意:這裏的iframe的name的值必定要和form的target的值同樣,這樣才能實現綁定
js代碼:
$("#uploadfile").on("load",function(){ //iframe裏面有個方法是onload,當上傳數據成功以後服務器返回數據時纔會觸發該事件 var rst=JSON.parse(this.contentDocument.body.textContent);//拿到iframe裏面的內容須要經過contentDocument才能拿到裏面的dom對象 if (rst.state){ var url="/"+rst.data; $('<img class="show-img" src="'+url+'">').appendTo("#imgs") } })
注意:拿到iframe裏面的內容須要經過contentDocument才能拿到裏面的dom對象通過實際檢測,當鼠標點擊提交速度比較快時,js經過ajax提交數據沒有問題,可是iframe就沒法提交全部數據。。。緣由是ajax是異步加載的,而iframe更像是經過瀏覽器打開了一個新標籤,等待服務端傳輸回來的數據。因此,當提交速度過快時沒法達到相應的效果。使用iframe的惟一一個好處目前來看也就是兼容老版本的瀏覽器罷了。。。隨着時間的流逝,這種方式終將被淘汰。