在使用者的本機裝置上選取檔案並與其互動,是網頁上最常用的功能之一。使用者可選取檔案並上傳至伺服器,例如分享相片或提交稅務文件時。這也讓網站能夠讀取及操控這些資料,而無須透過網路傳輸資料。本頁面將逐步說明如何使用 JavaScript 與檔案互動。
新版 File System Access API
File System Access API 提供一種方法,可讀取及寫入使用者本機系統中的檔案和目錄。這項功能適用於大多數以 Chromium 為基礎的瀏覽器,例如 Chrome 和 Edge。如需進一步瞭解,請參閱「File System Access API」。
由於 File System Access API 與所有瀏覽器皆不相容,因此建議您使用 browser-fs-access,這是一個輔助程式庫,可在可用的新 API 上使用,並在無法使用時改用舊版方法。
以傳統方式處理檔案
本指南說明如何使用舊版 JavaScript 方法與檔案互動。
選取檔案
您可以透過兩種主要方式選取檔案:使用 HTML 輸入元素,以及使用拖曳放置區域。
HTML 輸入元素
使用者選取檔案最簡單的方式,就是使用 <input type="file">
元素,所有主要瀏覽器都支援這項元素。點選後,使用者就能使用作業系統內建的檔案選取 UI 選取檔案,如果包含 multiple
屬性,則可選取多個檔案。當使用者選取檔案後,元素的 change
事件就會觸發。您可以透過 event.target.files
存取檔案清單,這是一個 FileList
物件。FileList
中的每個項目都是 File
物件。
<!-- The `multiple` attribute lets users select multiple files. -->
<input type="file" id="file-selector" multiple>
<script>
const fileSelector = document.getElementById('file-selector');
fileSelector.addEventListener('change', (event) => {
const fileList = event.target.files;
console.log(fileList);
});
</script>
以下範例可讓使用者透過作業系統內建的檔案選取 UI 選取多個檔案,然後將每個所選檔案記錄到控制台。
限制使用者可選取的檔案類型
在某些情況下,您可能會想限制使用者可選取的檔案類型。舉例來說,圖片編輯應用程式應只接受圖片,而非文字檔。如要設定檔案類型限制,請在輸入元素中新增 accept
屬性,指定系統接受的檔案類型:
<input type="file" id="file-selector" accept=".jpg, .jpeg, .png">
自訂拖曳功能
在某些瀏覽器中,<input type="file">
元素也是放置目標,可讓使用者將檔案拖曳至應用程式。不過,這個放置目標很小,可能不易使用。相反地,在使用 <input type="file">
元素提供核心功能後,您可以提供大型自訂拖放介面。
選擇放置區
放置點取決於應用程式的設計。您可能只想將視窗的一部分設為放置介面,但也可以使用整個視窗。
圖片壓縮應用程式 Squoosh 可讓使用者將圖片拖曳至視窗中的任何位置,然後按一下「選取圖片」來叫用 <input type="file">
元素。無論您選擇哪個放置區域,請務必讓使用者清楚知道可以將檔案拖曳到該介面。
定義放置區
如要將元素設為拖曳區,請為以下兩個事件建立事件監聽器:dragover
和 drop
。dragover
事件會更新瀏覽器 UI,以視覺方式指出拖曳放置動作正在建立檔案副本。使用者將檔案放到途徑後,系統會觸發 drop
事件。如同輸入元素,您可以透過 event.dataTransfer.files
存取檔案清單,這是 FileList
物件。FileList
中的每個項目都是 File
物件。
const dropArea = document.getElementById('drop-area');
dropArea.addEventListener('dragover', (event) => {
event.stopPropagation();
event.preventDefault();
// Style the drag-and-drop as a "copy file" operation.
event.dataTransfer.dropEffect = 'copy';
});
dropArea.addEventListener('drop', (event) => {
event.stopPropagation();
event.preventDefault();
const fileList = event.dataTransfer.files;
console.log(fileList);
});
event.stopPropagation()
和 event.preventDefault()
會停止瀏覽器的預設行為,並改為執行您的程式碼。否則,瀏覽器會離開您的網頁,並開啟使用者放入瀏覽器視窗的檔案。
如需實作示範,請參閱「自訂拖曳」。
目錄呢?
很抱歉,目前沒有適合使用 JavaScript 存取目錄的方法。
<input type="file">
元素上的 webkitdirectory
屬性可讓使用者選擇目錄。大多數主要瀏覽器都支援這項功能,但 Android 版 Firefox 和 iOS 版 Safari 除外。
如果啟用拖曳功能,使用者可能會嘗試將目錄拖曳至放置區。當放置事件觸發時,會包含目錄的 File
物件,但不會提供目錄中任何檔案的存取權。
讀取檔案中繼資料
File
物件包含檔案的中繼資料。大多數瀏覽器會提供檔案名稱、檔案大小和 MIME 類型,但根據平台不同,不同瀏覽器可能會提供不同的資訊或額外資訊。
function getMetadataForFileList(fileList) {
for (const file of fileList) {
// Not supported in Safari for iOS.
const name = file.name ? file.name : 'NOT SUPPORTED';
// Not supported in Firefox for Android or Opera for Android.
const type = file.type ? file.type : 'NOT SUPPORTED';
// Unknown cross-browser support.
const size = file.size ? file.size : 'NOT SUPPORTED';
console.log({file, name, type, size});
}
}
您可以在 input-type-file
示範中查看實際運作情形。
讀取檔案內容
使用 FileReader
將 File
物件的內容讀入記憶體。您可以指示 FileReader
以陣列緩衝區、資料網址或文字的形式讀取檔案:
function readImage(file) {
// Check if the file is an image.
if (file.type && !file.type.startsWith('image/')) {
console.log('File is not an image.', file.type, file);
return;
}
const reader = new FileReader();
reader.addEventListener('load', (event) => {
img.src = event.target.result;
});
reader.readAsDataURL(file);
}
這個範例會讀取使用者提供的 File
,然後將其轉換為資料網址,並使用該資料網址在 img
元素中顯示圖片。如要瞭解如何驗證使用者是否已選取圖片檔案,請參閱 read-image-file
示範。
監控檔案讀取進度
讀取大型檔案時,提供一些使用者體驗來告知使用者讀取進度有助於提升使用者體驗。為此,請使用 FileReader
提供的 progress
事件。progress
事件有兩個屬性:loaded
(讀取的數量) 和 total
(要讀取的數量)。
function readFile(file) {
const reader = new FileReader();
reader.addEventListener('load', (event) => {
const result = event.target.result;
// Do something with result
});
reader.addEventListener('progress', (event) => {
if (event.loaded && event.total) {
const percent = (event.loaded / event.total) * 100;
console.log(`Progress: ${Math.round(percent)}`);
}
});
reader.readAsDataURL(file);
}
主頁橫幅圖片由 Vincent Botta 提供,取自 Unsplash