<input type="file">
<input> 元素使用 type="file" 允許使用者從其裝置儲存中選擇一個或多個檔案。選擇後,可以使用 表單提交 將檔案上傳到伺服器,或者使用 JavaScript 程式碼和 檔案 API 進行操作。
試一試
值
檔案輸入的value屬性包含一個字串,表示所選檔案(或檔案)的路徑。如果尚未選擇任何檔案,則值為一個空字串 ("")。當用戶選擇多個檔案時,value表示他們選擇的檔案列表中的第一個檔案。可以使用輸入的HTMLInputElement.files屬性來識別其他檔案。
注意:該值始終是檔名,並在其前面添加了C:\fakepath\,這不是檔案的真實路徑。這是為了防止惡意軟體猜測使用者的檔案結構。
其他屬性
除了所有<input>元素共享的常用屬性外,型別為file的輸入還支援以下屬性。
accept
accept屬性值是一個字串,用於定義檔案輸入應該接受的檔案型別。此字串是唯一檔案型別指定符的逗號分隔列表。因為給定的檔案型別可以透過多種方式識別,所以當您需要特定格式的檔案時,提供一套完整的型別指定符非常有用。
例如,Microsoft Word檔案可以透過多種方式識別,因此接受Word檔案的站點可能會使用如下所示的<input>
<input
type="file"
id="docpicker"
accept=".doc,.docx,.xml,application/msword,application/vnd.openxmlformats-officedocument.wordprocessingml.document" />
capture
multiple
當指定了multiple布林屬性時,檔案輸入允許使用者選擇多個檔案。
非標準屬性
除了上面列出的屬性之外,一些瀏覽器還提供了以下非標準屬性。您應該儘量避免使用它們,因為這樣做會限制您的程式碼在未實現它們的瀏覽器中執行的能力。
webkitdirectory
布林webkitdirectory屬性(如果存在)表示在檔案選擇器介面中,只有目錄可供使用者選擇。有關其他詳細資訊和示例,請參閱HTMLInputElement.webkitdirectory。
雖然最初僅在基於WebKit的瀏覽器中實現,但webkitdirectory也可用於Microsoft Edge以及Firefox 50及更高版本。但是,即使它具有相對廣泛的支援,它仍然不是標準的,除非您別無選擇,否則不應使用它。
唯一的檔案型別說明符
唯一檔案型別指定符是一個字串,用於描述使用者可以在型別為file的<input>元素中選擇的某種檔案型別。每個唯一檔案型別指定符可以採用以下格式之一
- 以句點 (".") 字元開頭的有效不區分大小寫的檔名副檔名。例如:
.jpg、.pdf或.doc。 - 有效的MIME型別字串,不帶副檔名。
- 字串
audio/*表示“任何音訊檔案”。 - 字串
video/*表示“任何影片檔案”。 - 字串
image/*表示“任何影像檔案”。
accept屬性採用一個字串作為其值,該字串包含一個或多個這些唯一檔案型別指定符,並以逗號分隔。例如,需要可以顯示為影像的內容(包括標準影像格式和PDF檔案)的檔案選擇器可能如下所示
<input type="file" accept="image/*,.pdf" />
使用檔案輸入
一個基本示例
<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>
這將產生以下輸出
無論使用者的裝置或作業系統如何,檔案輸入都提供一個按鈕,該按鈕會開啟一個檔案選擇器對話方塊,允許使用者選擇檔案。
如上所示,包含multiple屬性指定可以一次選擇多個檔案。使用者可以透過其所選平臺允許的任何方式(例如,按住Shift或Control然後單擊)從檔案選擇器中選擇多個檔案。如果您只希望使用者為每個<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)。
限制可接受的檔案型別
通常,您不希望使用者能夠選擇任意型別的檔案;相反,您通常希望他們選擇特定型別或型別的檔案。例如,如果您的檔案輸入允許使用者上傳個人資料圖片,您可能希望他們選擇與網路相容的影像格式,例如JPEG或PNG。
可以使用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文件的檔案。
讓我們看一個更完整的示例
<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>
這將生成與上一個示例類似的輸出
它可能看起來很相似,但如果您嘗試使用此輸入選擇檔案,您會發現檔案選擇器只允許您選擇accept值中指定的檔案型別(確切的介面在不同的瀏覽器和作業系統中有所不同)。
accept屬性不會驗證所選檔案的型別;它為瀏覽器提供提示,以引導使用者選擇正確型別的檔案。使用者仍然可以(在大多數情況下)切換檔案選擇器中的一個選項,使其能夠覆蓋此選項並選擇他們想要的任何檔案,然後選擇不正確的檔案型別。
因此,您應該確保accept屬性由適當的伺服器端驗證支援。
檢測取消操作
當用戶沒有更改他們的選擇,重新選擇之前選擇的的檔案時,會觸發cancel事件。當檔案選擇器對話方塊透過“取消”按鈕或escape鍵關閉或取消時,也會觸發cancel事件。
例如,以下程式碼將在使用者關閉彈出視窗而未選擇檔案時記錄到控制檯
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();
註釋
- 您不能從指令碼設定檔案選擇器的值 - 執行以下操作無效js
const input = document.querySelector("input[type=file]"); input.value = "foo"; - 當使用
<input type="file">選擇檔案時,原始檔的真實路徑不會顯示在輸入的value屬性中,原因很明顯,是為了安全起見。而是顯示檔名,並在其前面添加了C:\fakepath\。此怪癖有一些歷史原因,但在所有現代瀏覽器中都得到支援,事實上,它在規範中定義。
示例
在此示例中,我們將提供一個稍微高階一點的檔案選擇器,它利用了HTMLInputElement.files屬性中可用的檔案資訊,並展示了一些巧妙的技巧。
注意:您可以在GitHub上檢視此示例的完整原始碼 - file-example.html(也可以檢視其執行情況)。我們不會解釋CSS;JavaScript是主要焦點。
首先,讓我們看一下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並像按鈕一樣設定標籤的樣式,這樣使用者就會知道如果要上傳檔案,需要與之互動。
const input = document.querySelector("input");
const preview = document.querySelector(".preview");
input.style.opacity = 0;
注意:使用opacity來隱藏檔案輸入,而不是visibility: hidden或display: none,因為輔助技術將後兩種樣式解釋為檔案輸入不可互動。
接下來,我們向輸入新增一個事件監聽器,以監聽其所選值的更改(在本例中,當選擇檔案時)。事件監聽器呼叫我們自定義的updateImageDisplay()函式。
input.addEventListener("change", updateImageDisplay);
每當呼叫updateImageDisplay()函式時,我們都會
- 使用
while迴圈清空預覽<div>中的先前內容。 - 獲取包含所有已選擇檔案資訊的
FileList物件,並將其儲存在一個名為curFiles的變數中。 - 檢查是否未選擇任何檔案,方法是檢查
curFiles.length是否等於0。如果是,則在預覽<div>中列印一條訊息,說明未選擇任何檔案。 - 如果已選擇檔案,則遍歷每個檔案,並將有關該檔案的資訊列印到預覽
<div>中。這裡需要注意以下幾點 - 我們使用自定義的
validFileType()函式來檢查檔案是否為正確的型別(例如,accept屬性中指定的影像型別)。 - 如果是,我們
- 將檔名和檔案大小列印到前一個
<div>(從file.name和file.size獲取)內的列表項中。自定義的returnFileSize()函式以易於閱讀的格式返回以位元組/KB/MB表示的大小(預設情況下,瀏覽器以絕對位元組報告大小)。 - 透過呼叫
URL.createObjectURL(file)生成影像的縮圖預覽。然後,透過建立一個新的<img>並將它的src設定為縮圖,將影像插入列表項中。
- 將檔名和檔案大小列印到前一個
- 如果檔案型別無效,則在列表項內顯示一條訊息,告訴使用者需要選擇不同的檔案型別。
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。
// 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格式的大小。
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)。因此,我們使用1e3(1000)和1e6(100000)而不是1024和1048576。在您的應用程式中,如果精確的大小很重要,則應向用戶明確傳達單位系統。
示例如下;試一試
技術摘要
規範
| 規範 |
|---|
| HTML標準 # file-upload-state-(type=file) |
瀏覽器相容性
BCD表格僅在瀏覽器中載入
另請參閱
- 從Web應用程式中使用檔案——包含許多其他與
<input type="file">和檔案API相關的有用示例。 - CSS屬性的相容性