一個小時帶你總結前端上傳檔案的方法(整理分享)

2022-02-08 19:00:50
本篇文章給大家帶來了關於前端上傳檔案的相關知識,其中包括傳統開發模式上傳、前後端分離上傳以及ajax上傳等等相關問題,希望對大家有幫助。

上傳檔案

專案中會有很多檔案上傳的需求,例如:頭像上傳、表格檔案、word檔案等…

上傳必備表單元素:

<input type="file">

進行檔案上傳的時候,
1.表單必須是post請求
2.表單必須宣告不要對資料進行編碼 - enctype=multipart/form-data

傳送資料的格式就是鍵值對的形式,且資料都是js的資料型別,但檔案進行傳輸的時候,只有兩種形式去傳輸:

  1. 以字串的形式去描述一個檔案
  2. 以檔案流的形式去描述一個檔案

傳統開發模式上傳

前後端混在一起開發

傳統開發模式的上傳需要將表單中選擇的檔案傳送給後端,讓後端做上傳:

<form action="./upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="avatar">
    <input type="submit" value="上傳"></form>

此時的表單中必須有enctype這個屬性,這個屬性的說明如下圖:

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-FJ4TCM6S-1623079075591)(media/1621737905322.png)]

點選上傳按鈕後,後端對檔案進行上傳處理,以php為例:

echo "上傳檔名: " . $_FILES["avatar"]["name"] . "<br>";  上傳檔案的名稱
echo "檔案型別: " . $_FILES["avatar"]["type"] . "<br>";  上傳檔案的型別
echo "檔案大小: " . ($_FILES["avatar"]["size"] / 1024) . " kB<br>";  上傳檔案的大小,以位元組計
echo "檔案臨時儲存的位置: " . $_FILES["avatar"]["tmp_name"];  儲存在伺服器的檔案的臨時副本的名稱
echo $_FILES["file"]["error"]  由檔案上傳導致的錯誤程式碼

將檔案儲存到伺服器中:

move_uploaded_file($_FILES["avatar"]["tmp_name"], "upload/" . $_FILES["avatar"]["name"]);
echo "檔案儲存在: " . "upload/" . $_FILES["avatar"]["name"];

在實際開發中,為了提高效率,通常都會使用前後端分離開發。

前後端分離上傳

前端做前端,後端做後端,最終使用介面檔案對接 - 核心技術是 ajax

前後端分離開發,應用的主要技術就是ajax。上傳同樣可以使用ajax來上傳。

FormData是js內建的一個建構函式,構造出來的物件可以識別檔案資訊。

使用方式:

構造FormData物件,將檔案資訊新增到FormData物件中,然後上傳。

檔案資訊在檔案選擇控制元件中:表單.files

例:

<body>
    <input type="file" name="avatar">
    <input type="button" value="上傳"></body><script>document.querySelector('[type="button"]').onclick = function(){
	 console.log(document.querySelector('[type="file"]').files)}</script>

在這裡插入圖片描述

FormData物件有一個特點,將檔案資訊新增進去後,直接列印不能看到檔案資訊,需要使用for of遍歷才能看到:

var formdata = new FormData();var fileinfo = document.querySelector('[type="file"]').files[0];formdata.append('avatar',fileinfo) / 將檔案資訊新增到FormData物件中
console.log(formdata)for(var v of formdata){
    console.log(v)}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-w0A4kjb7-1623079075609)(media/1621739596218.png)]

FormData物件中也可以新增別的資料,進行一起提交:

formdata.append('avatar',fileinfo)formdata.append('age',12)for(var v of formdata){
    console.log(v)}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-E4L8JjjG-1623079075612)(media/1621739699971.png)]

從FormData物件中刪除一個資料,使用:

formdata.delete(鍵)

有時候,我們在一個表單中需要上傳多個檔案,此時,FormData中可以不用追加一個檔案資訊,可以在構造FormData物件的時候,將整個表單物件傳入,他會自動識別所有資料:

<body><form action="">
    <input type="text" name="age" value="20">
    <input type="file" name="avatar">
    <input type="button" value="上傳"></form></body><script>document.querySelector('[type="button"]').onclick = function(){
    var formdata = new FormData(document.querySelector('form'));
    for(var v of formdata){
        console.log(v)
    }}</script>

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片儲存下來直接上傳(img-UfREm9lD-1623079075616)(media/1621739964694.png)]

當使用FormData上傳的時候,將FormData物件當做資料傳入,不需要修改請求頭,瀏覽器會自動修改。

此時已經實現了前後端分離上傳了,但是正常專案中都會有一個預覽圖片的功能。

我們可以讓後端在實現上傳後,將上傳以後的檔名稱傳送給前端,讓前端渲染返回的圖片路徑。

但這樣是在上傳以後預覽的,假設我們選擇了檔案以後,就想看看這個檔案是否要上傳,也就是在上傳之前要預覽的話,還是沒有辦法實現。

我們可以利用H5提供的FileReader來讀取檔案並預覽,然後決定是否要上傳。

ajax上傳

ajax進行上傳後

 var xhr = new XMLHttpRequest;
    xhr.onreadystatechange = function(){
        if(xhr.readyState === 4){
            if(xhr.status>=200 && xhr.status<300){
                var res = xhr.responseText;
                // console.log(res);
                if(res==1){
                     alert('上傳成功')
                     location.reload()
                }
            }
        }
    }
    xhr.open('post','2-upload.php')

將檔案資料放在send中進行傳送
需要藉助H5提供的建構函式FormData - 用來識別檔案資訊

var fd = new FormData()

將檔案資訊放在fd這個物件中 - 用fd的append方法

檔案資訊在哪裡?

var file = document.querySelector('[type="file"]')
    // console.dir(file);
    var fileinfo = file.files[0] / 檔案資訊

append方法,是將檔案放入這個物件中,物件就需要鍵值對,引數1是鍵,引數2是檔案資訊

fd.append('avatar',fileinfo)

fd有一個特性,就是直接列印他, 看不到其中的內容 需要遍歷才能看到其中的資料 - 必須使用 for of

for(var value of fd){
         console.log(value);
    }

fd除了能新增檔案資訊,還可以新增資料

fd.append('username',document.querySelector('[name="username"]').value)

上傳檔案的時候,利用FormData,裡面就有了資料和檔案資訊,其實最終檔案和資料以二進位制資料流進行傳送的,不需要設定請求頭,因為ajax會自動調整

檔案資料其實就是fd

php:

現在能列印出資料,檔案存到了臨時目錄中
上傳就是將臨時檔案移動到伺服器中

header("content-type:text/html;charset=utf8");echo "<pre>";print_r($_FILES);move_uploaded_file($_FILES['avatar']['tmp_name'],'./upload/'.$_FILES['avatar']['name']);// echo '上傳成功';echo './upload/'.$_FILES['avatar']['name'];
 echo "<script>
     alert('上傳成功')
     location.assign('./1-上傳表單.html')

ajax 上傳前:

當檔案選擇器中的資料發生了變化就要讀取並預覽
讀取並預覽 - 藉助H5提供的FileReader - 讀取檔案是非同步讀取
建構函式需要new

document.querySelector('[type="file"]').onchange = function(){var fr = new FileReader();

readAsArrayBuffer - 將資料讀取成一個Buffer陣列

var fileinfo = this.files[0]

引數要一個檔案物件 - 結果是一個buffer

fr.readAsArrayBuffer(fileinfo)

引數要一個檔案物件 - 結果是一個二進位制資料 - 適用於多媒體檔案

fr.readAsBinaryString(fileinfo)

結果是一個可以當做路徑使用的資料 - base64字串 - 適用於圖片

fr.readAsDataURL(fileinfo)

在load事件中,讀取完成後獲取讀取出來的資料
load事件在讀取完成的時候觸發

fr.onload = function(){
        / result屬性是讀取出來的內容        / console.log(fr.result);
        / 建立img標籤        var img = document.createElement('img')
        img.src = fr.result;
        document.body.appendChild(img)

FileReader讀取檔案

FileReader也是js內建的一個建構函式,主要功能是用來讀取檔案,讀取檔案為非同步讀取。

var fr = new FileReader()  建立讀取物件// 該物件的讀取方法:fr.readAsDataUrl(檔案資訊)  將檔案讀取為base64字串 - 通常用於圖片檔案,讀取結果可以作為圖片的src使用
fr.readAsArrayBuffer(檔案資訊)  將檔案讀取為二進位制資料流 - 通常用於多媒體檔案
fr.readAsText(檔案資訊)  將檔案讀取為字串 - 通常用於檔案檔案

物件監聽的事件:

abort事件:在讀取被中斷的時候觸發
error事件:讀取發生錯誤的時候觸發
load事件:在讀取完成的時候觸發 - 常用語讀取完成後獲取資料
loadstart事件:在讀取開始的時候觸發
loadend事件:在讀取結束的時候觸發
progress事件:在讀取過程中觸發

例:

fr.onload = function(){
  讀取結果為:物件.result 或 事件物件.target.result
    console.log(fr.result)  此時這個資料就可以作為img的src進行圖片預覽}

base64是指:小寫字母+大寫字母+數位+加號+等於號 共64個字元

jquery上傳

data位置就直接寫formData就好了

設定一個content-type為false表示jquery不要設定請求頭

設定一個processData為false,表示query不要修改資料格式

<form action="javascript:;">
    <input type="file" name="avatar">
    <input type="text" name="username">
    <br>
    <input type="button" value="上傳"></form>

我們可以在new的時候,將表單元素放在建構函式中 - 預設能將表單中的資料,新增到這個物件中

$('[type="button"]').click(function()
    var fd = new FormData($('form')[0])

    $.ajax({
        url:"2-upload.php",
        method:"post",
         jquery上傳用 FormData
        data:fd,
        contentType:false,  不讓jQuery的ajax修改請求頭
        processData:false,  不讓jquery的ajax編碼資料        success:res=>{
            console.log(res);
        }
        
    })})

webWorker

大量運算的程式碼,可以作為一個非同步執行緒執行
需要將這段程式碼單獨放在一個檔案中
需要new一個worker物件 - 這個建構函式需要在伺服器環境中執行

woker需要一個事件,當檔案完成以後獲取裡面的資料
可以在事件中,接收到檔案中匯出的資料

woker.onmessage = function(e){
    資料就在事件物件的data屬性中
    console.log(e.data);}

當業務邏輯需要的計算量比較大的時候,同步程式碼會阻塞下面的程式碼繼續執行,此時需要將這個大計算量的程式碼另外開闢一個新的執行緒進行執行,這個執行緒也是非同步執行的,但需要將在新執行緒中執行的程式碼單獨放在一個js檔案中,使用方式:

var w = new Worker(需要非同步執行的js檔案)

如果在主執行緒中需要這個執行緒中返回的資料,在這個執行緒中使用postMessage來返回:

postMessage(資料)

主執行緒中接收返回出來的資料:

w.onmessage = function(e){
    e.data // 是非同步執行緒中返回出來的資料}

離線快取

離線快取的作用:在馬上斷網之後,依舊可以存取到快取下來的檔案。比較雞肋。該技術在2020年8月已經被棄用了。

使用方式:

使用規則        1. 需要你自定義一個 .manifest 檔案        2. 再你書寫 html 檔案的時候
          => 如果這個 html 檔案需要快取規則
          => 再 html 標籤上新增一個 manifest 屬性
          => 值就寫你的快取規則檔案        3. 第一次開啟頁面的時候
          => 就會按照你書寫的快取規則去快取檔案

例:

第一行必須要寫上
CACHE MANIFEST
以註釋的形式書寫一個版本號
app version 1.0

表示你要快取的檔案
CACHE:
./index.html
./css/index.css

表示必須需要網路環境才可以請求的檔案
一般我們會書寫 星號(*), 表示除了 CACHE 裡面書寫的檔案, 其他的去過沒有網路環境就報錯
NETWORK:
*

當你再一個離線環境下存取一些沒有的頁面的時候
使用一個什麼內容替代
FALLBACK:

  • ./404.html

事件迴圈面試題:

<script>console.log(1)setTimeout(()=>{ console.log(2) },0) new Promise(resolve=>{
    console.log(3)
    resolve()}).then(()=>{ 
    console.log(4)})setTimeout(()=>{ 
    console.log(5)
    new Promise(resolve=>{
        console.log(6)
        setTimeout(()=>{ 
            console.log(7)
        })
        resolve()
    }).then(()=>{ 
        console.log(8)
    })},500)new Promise(resolve=>{
    console.log(9)
    resolve()}).then(()=>{ 
    console.log(10)
    setTimeout(()=>{ 
        console.log(11)
    },0)})console.log(12)</script>

答案:1 3 9 12 4 10 2 11 5 6 8 7

更多程式設計相關知識,請存取:!!

以上就是一個小時帶你總結前端上傳檔案的方法(整理分享)的詳細內容,更多請關注TW511.COM其它相關文章!