<input type="file">

<input> 元素使用 type="file" 允許使用者從其裝置儲存中選擇一個或多個檔案。選擇後,可以使用 表單提交 將檔案上傳到伺服器,或者使用 JavaScript 程式碼和 檔案 API 進行操作。

試一試

檔案輸入的value屬性包含一個字串,表示所選檔案(或檔案)的路徑。如果尚未選擇任何檔案,則值為一個空字串 ("")。當用戶選擇多個檔案時,value表示他們選擇的檔案列表中的第一個檔案。可以使用輸入的HTMLInputElement.files屬性來識別其他檔案。

注意:該值始終是檔名,並在其前面添加了C:\fakepath\,這不是檔案的真實路徑。這是為了防止惡意軟體猜測使用者的檔案結構。

其他屬性

除了所有<input>元素共享的常用屬性外,型別為file的輸入還支援以下屬性。

accept

accept屬性值是一個字串,用於定義檔案輸入應該接受的檔案型別。此字串是唯一檔案型別指定符的逗號分隔列表。因為給定的檔案型別可以透過多種方式識別,所以當您需要特定格式的檔案時,提供一套完整的型別指定符非常有用。

例如,Microsoft Word檔案可以透過多種方式識別,因此接受Word檔案的站點可能會使用如下所示的<input>

html
<input
  type="file"
  id="docpicker"
  accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />

capture

capture屬性值是一個字串,用於指定要用於捕獲影像或影片資料的攝像頭(如果accept屬性指示輸入應為這些型別之一)。值user表示應使用面向使用者的攝像頭和/或麥克風。值environment指定應使用面向外部的攝像頭和/或麥克風。如果缺少此屬性,則使用者代理可以自由決定該怎麼做。如果請求的面向模式不可用,則使用者代理可能會回退到其首選的預設模式。

注意:capture以前是一個布林屬性,如果存在,則請求使用裝置的媒體捕獲裝置(如攝像頭或麥克風),而不是請求檔案輸入。

multiple

當指定了multiple布林屬性時,檔案輸入允許使用者選擇多個檔案。

非標準屬性

除了上面列出的屬性之外,一些瀏覽器還提供了以下非標準屬性。您應該儘量避免使用它們,因為這樣做會限制您的程式碼在未實現它們的瀏覽器中執行的能力。

webkitdirectory

布林webkitdirectory屬性(如果存在)表示在檔案選擇器介面中,只有目錄可供使用者選擇。有關其他詳細資訊和示例,請參閱HTMLInputElement.webkitdirectory

雖然最初僅在基於WebKit的瀏覽器中實現,但webkitdirectory也可用於Microsoft Edge以及Firefox 50及更高版本。但是,即使它具有相對廣泛的支援,它仍然不是標準的,除非您別無選擇,否則不應使用它。

唯一的檔案型別說明符

唯一檔案型別指定符是一個字串,用於描述使用者可以在型別為file<input>元素中選擇的某種檔案型別。每個唯一檔案型別指定符可以採用以下格式之一

  • 以句點 (".") 字元開頭的有效不區分大小寫的檔名副檔名。例如:.jpg.pdf.doc
  • 有效的MIME型別字串,不帶副檔名。
  • 字串audio/*表示“任何音訊檔案”。
  • 字串video/*表示“任何影片檔案”。
  • 字串image/*表示“任何影像檔案”。

accept屬性採用一個字串作為其值,該字串包含一個或多個這些唯一檔案型別指定符,並以逗號分隔。例如,需要可以顯示為影像的內容(包括標準影像格式和PDF檔案)的檔案選擇器可能如下所示

html
<input type="file" accept="image/*,.pdf" />

使用檔案輸入

一個基本示例

html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">Choose file to upload</label>
    <input type="file" id="file" name="file" multiple />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

這將產生以下輸出

注意:您也可以在GitHub上找到此示例 - 請參閱原始碼,還可以檢視其執行情況

無論使用者的裝置或作業系統如何,檔案輸入都提供一個按鈕,該按鈕會開啟一個檔案選擇器對話方塊,允許使用者選擇檔案。

如上所示,包含multiple屬性指定可以一次選擇多個檔案。使用者可以透過其所選平臺允許的任何方式(例如,按住ShiftControl然後單擊)從檔案選擇器中選擇多個檔案。如果您只希望使用者為每個<input>選擇一個檔案,請省略multiple屬性。

獲取所選檔案的資訊

所選檔案由元素的HTMLInputElement.files屬性返回,該屬性是一個包含File物件列表的FileList物件。FileList的行為類似於陣列,因此您可以檢查其length屬性以獲取所選檔案的數量。

每個File物件包含以下資訊

name

檔案的名稱。

lastModified

一個數字,指定檔案上次修改的日期和時間,以自UNIX紀元(1970年1月1日午夜)以來的毫秒數表示。

lastModifiedDate 已棄用

一個表示檔案上次修改日期和時間的Date物件。此屬性已棄用,不應使用。請改用lastModified

size

檔案的大小(以位元組為單位)。

type

檔案的MIME型別

webkitRelativePath 非標準

一個字串,指定檔案相對於在目錄選擇器中選擇的基目錄的路徑(即,設定了webkitdirectory屬性的檔案選擇器)。此屬性是非標準的,應謹慎使用。

注意:您可以在所有現代瀏覽器中設定和獲取HTMLInputElement.files的值;這最近新增到Firefox中,在版本57中(請參閱Firefox錯誤1384030)。

限制可接受的檔案型別

通常,您不希望使用者能夠選擇任意型別的檔案;相反,您通常希望他們選擇特定型別或型別的檔案。例如,如果您的檔案輸入允許使用者上傳個人資料圖片,您可能希望他們選擇與網路相容的影像格式,例如JPEGPNG

可以使用accept屬性指定可接受的檔案型別,該屬性採用允許的副檔名或MIME型別的逗號分隔列表。一些示例

  • accept="image/png"accept=".png" - 接受PNG檔案。
  • accept="image/png, image/jpeg"accept=".png, .jpg, .jpeg" - 接受PNG或JPEG檔案。
  • accept="image/*" - 接受任何具有image/* MIME型別的檔案。(許多移動裝置在使用此選項時也允許使用者使用攝像頭拍攝照片。)
  • accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" - 接受任何類似於MS Word文件的檔案。

讓我們看一個更完整的示例

html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="profile_pic">Choose file to upload</label>
    <input
      type="file"
      id="profile_pic"
      name="profile_pic"
      accept=".jpg, .jpeg, .png" />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

這將生成與上一個示例類似的輸出

注意:您也可以在GitHub上找到此示例 - 請參閱原始碼,還可以檢視其執行情況

它可能看起來很相似,但如果您嘗試使用此輸入選擇檔案,您會發現檔案選擇器只允許您選擇accept值中指定的檔案型別(確切的介面在不同的瀏覽器和作業系統中有所不同)。

accept屬性不會驗證所選檔案的型別;它為瀏覽器提供提示,以引導使用者選擇正確型別的檔案。使用者仍然可以(在大多數情況下)切換檔案選擇器中的一個選項,使其能夠覆蓋此選項並選擇他們想要的任何檔案,然後選擇不正確的檔案型別。

因此,您應該確保accept屬性由適當的伺服器端驗證支援。

檢測取消操作

當用戶沒有更改他們的選擇,重新選擇之前選擇的的檔案時,會觸發cancel事件。當檔案選擇器對話方塊透過“取消”按鈕或escape鍵關閉或取消時,也會觸發cancel事件。

例如,以下程式碼將在使用者關閉彈出視窗而未選擇檔案時記錄到控制檯

js
const elem = document.createElement("input");
elem.type = "file";
elem.addEventListener("cancel", () => {
  console.log("Cancelled.");
});
elem.addEventListener("change", () => {
  if (elem.files.length == 1) {
    console.log("File selected: ", elem.files[0]);
  }
});
elem.click();

註釋

  1. 您不能從指令碼設定檔案選擇器的值 - 執行以下操作無效
    js
    const input = document.querySelector("input[type=file]");
    input.value = "foo";
    
  2. 當使用<input type="file">選擇檔案時,原始檔的真實路徑不會顯示在輸入的value屬性中,原因很明顯,是為了安全起見。而是顯示檔名,並在其前面添加了C:\fakepath\。此怪癖有一些歷史原因,但在所有現代瀏覽器中都得到支援,事實上,它在規範中定義

示例

在此示例中,我們將提供一個稍微高階一點的檔案選擇器,它利用了HTMLInputElement.files屬性中可用的檔案資訊,並展示了一些巧妙的技巧。

注意:您可以在GitHub上檢視此示例的完整原始碼 - file-example.html也可以檢視其執行情況)。我們不會解釋CSS;JavaScript是主要焦點。

首先,讓我們看一下HTML

html
<form method="post" enctype="multipart/form-data">
  <div>
    <label for="image_uploads">Choose images to upload (PNG, JPG)</label>
    <input
      type="file"
      id="image_uploads"
      name="image_uploads"
      accept=".jpg, .jpeg, .png"
      multiple />
  </div>
  <div class="preview">
    <p>No files currently selected for upload</p>
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

這與我們之前看到的類似 - 沒有特殊的內容需要評論。

接下來,讓我們逐步瞭解JavaScript。

在指令碼的第一行,我們獲取了表單輸入本身以及類為.preview<div>元素的引用。接下來,我們隱藏了<input>元素 - 我們這樣做是因為檔案輸入往往很醜、難以設定樣式並且在不同瀏覽器的設計中不一致。您可以透過單擊其<label>來啟用input元素,因此最好在視覺上隱藏input並像按鈕一樣設定標籤的樣式,這樣使用者就會知道如果要上傳檔案,需要與之互動。

js
const input = document.querySelector("input");
const preview = document.querySelector(".preview");

input.style.opacity = 0;

注意:使用opacity來隱藏檔案輸入,而不是visibility: hiddendisplay: none,因為輔助技術將後兩種樣式解釋為檔案輸入不可互動。

接下來,我們向輸入新增一個事件監聽器,以監聽其所選值的更改(在本例中,當選擇檔案時)。事件監聽器呼叫我們自定義的updateImageDisplay()函式。

js
input.addEventListener("change", updateImageDisplay);

每當呼叫updateImageDisplay()函式時,我們都會

  • 使用while迴圈清空預覽<div>中的先前內容。

  • 獲取包含所有已選擇檔案資訊的FileList物件,並將其儲存在一個名為curFiles的變數中。
  • 檢查是否未選擇任何檔案,方法是檢查curFiles.length是否等於0。如果是,則在預覽<div>中列印一條訊息,說明未選擇任何檔案。
  • 如果已選擇檔案,則遍歷每個檔案,並將有關該檔案的資訊列印到預覽<div>中。這裡需要注意以下幾點
  • 我們使用自定義的validFileType()函式來檢查檔案是否為正確的型別(例如,accept屬性中指定的影像型別)。
  • 如果是,我們
    • 將檔名和檔案大小列印到前一個<div>(從file.namefile.size獲取)內的列表項中。自定義的returnFileSize()函式以易於閱讀的格式返回以位元組/KB/MB表示的大小(預設情況下,瀏覽器以絕對位元組報告大小)。
    • 透過呼叫URL.createObjectURL(file)生成影像的縮圖預覽。然後,透過建立一個新的<img>並將它的src設定為縮圖,將影像插入列表項中。
  • 如果檔案型別無效,則在列表項內顯示一條訊息,告訴使用者需要選擇不同的檔案型別。
js
function updateImageDisplay() {
  while (preview.firstChild) {
    preview.removeChild(preview.firstChild);
  }

  const curFiles = input.files;
  if (curFiles.length === 0) {
    const para = document.createElement("p");
    para.textContent = "No files currently selected for upload";
    preview.appendChild(para);
  } else {
    const list = document.createElement("ol");
    preview.appendChild(list);

    for (const file of curFiles) {
      const listItem = document.createElement("li");
      const para = document.createElement("p");
      if (validFileType(file)) {
        para.textContent = `File name ${file.name}, file size ${returnFileSize(
          file.size,
        )}.`;
        const image = document.createElement("img");
        image.src = URL.createObjectURL(file);
        image.alt = image.title = file.name;

        listItem.appendChild(image);
        listItem.appendChild(para);
      } else {
        para.textContent = `File name ${file.name}: Not a valid file type. Update your selection.`;
        listItem.appendChild(para);
      }

      list.appendChild(listItem);
    }
  }
}

自定義的validFileType()函式將一個File物件作為引數,然後使用Array.prototype.includes()檢查fileTypes中的任何值是否與檔案的type屬性匹配。如果找到匹配項,則該函式返回true。如果未找到匹配項,則返回false

js
// https://mdn.club.tw/en-US/docs/Web/Media/Formats/Image_types
const fileTypes = [
  "image/apng",
  "image/bmp",
  "image/gif",
  "image/jpeg",
  "image/pjpeg",
  "image/png",
  "image/svg+xml",
  "image/tiff",
  "image/webp",
  "image/x-icon",
];

function validFileType(file) {
  return fileTypes.includes(file.type);
}

returnFileSize()函式接收一個數字(以位元組為單位,取自當前檔案的size屬性),並將其轉換為易於閱讀的位元組/KB/MB格式的大小。

js
function returnFileSize(number) {
  if (number < 1e3) {
    return `${number} bytes`;
  } else if (number >= 1e3 && number < 1e6) {
    return `${(number / 1e3).toFixed(1)} KB`;
  } else {
    return `${(number / 1e6).toFixed(1)} MB`;
  }
}

注意:這裡的“KB”和“MB”單位使用SI字首約定,即1KB = 1000B,類似於macOS。不同的系統以不同的方式表示檔案大小——例如,Ubuntu使用IEC字首,其中1KiB = 1024B,而RAM規格通常使用SI字首來表示2的冪(1KB = 1024B)。因此,我們使用1e31000)和1e6100000)而不是10241048576。在您的應用程式中,如果精確的大小很重要,則應向用戶明確傳達單位系統。

示例如下;試一試

技術摘要

表示所選檔案路徑的字串。
事件 changeinputcancel
支援的常用屬性 required
其他屬性 acceptcapturemultiple
IDL屬性 filesvalue
DOM介面

HTMLInputElement

方法 select()
隱式ARIA角色 沒有對應的角色

規範

規範
HTML標準
# file-upload-state-(type=file)

瀏覽器相容性

BCD表格僅在瀏覽器中載入

另請參閱