Jeff的隨手筆記

學習當一個前端工程師

0%

『菜鳥的踩坑筆記』-Input File

前言

第一次接觸 Input File (檔案輸入) 是在 AC 做畢業專案時碰到的,但當時並不是我負責這個課題,只有稍微去了解一下,卻沒有很仔細研究,想說之後遇到再深入探討,沒想到這麼快就派上用場了。

最近,在處理一個專案時就碰到需要新增檔案上傳的功能,這讓我不得不重新研究一下這個前端開發中常見但容易被忽略的功能。

檔案上傳在現代網頁應用中扮演著重要的角色,無論是上傳個人頭像、提交文件報告,還是處理大型數據集,都需要良好的檔案上傳機制。

作為前端工程師,理解 Input File 的運作原理不僅能幫助我們實現基本的檔案上傳功能,還能優化使用者體驗,處理各種常見的邊界情況,如檔案大小限制、格式驗證、多檔案上傳等。此外,隨著現代瀏覽器功能的增強,我們也有了更多工具來優化這個過程。

以下我將分享自己對 Input File 的簡單理解:

基本語法

HTML 中最基本的檔案上傳元素是 <input type="file">,基本用法如下:

1
2
3
4
5
6
<input
type="file"
id="file-uploader"
accept="image/*"
multiple="multiple"
/>

accept 屬性(限制檔案類型)

accept 屬性讓我們能夠限制使用者可以選擇的檔案類型:

  • accept="image/png":只接受 PNG 圖片
  • accept="image/*":接受所有圖片格式
  • accept=".doc,.docx,.pdf":接受特定副檔名
  • accept="image/png, image/jpeg":接受 PNG 和 JPEG 格式

multiple 屬性

控制是否可以選擇多個檔案:

  • 設定 multiple="multiple" 可以允許一次選擇多個檔案
  • 不設定則一次只能選擇一個檔案

capture 屬性

用於移動設備,可指定使用相機或麥克風:

1
2
<!-- 使用後置相機拍攝 -->
<input type="file" accept="image/*" capture="environment" />

取得上傳的檔案

當使用者選擇檔案後,我們要如何處理這個檔案?首先要透過 JavaScript 取得檔案資訊:

1
2
3
4
5
6
7
8
9
10
11
const fileUploader = document.querySelector('#file-uploader');

fileUploader.addEventListener('change', (e) => {
const file = e.target.files[0]; // 取得上傳的第一個檔案

// 可以看到檔案的基本資訊
console.log('檔案名稱:', file.name);
console.log('檔案大小:', file.size);
console.log('檔案類型:', file.type);
});

這樣我們就可以進行後續操作了。

圖片預覽功能

在實務上,我們常常需要讓使用者看到他們上傳的圖片預覽。有兩種常用的方法:

方法一:使用 FileReader(推薦)

FileReader 是一個強大的 API,可以讀取檔案的內容,特別適合用來生成圖片預覽:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function showPreview(file) {
const reader = new FileReader();

// 當讀取完成時
reader.onload = (e) => {
const preview = document.querySelector('#preview-img');
preview.src = e.target.result; // 設定圖片來源
};

// 開始讀取檔案
reader.readAsDataURL(file);
}

// 使用方式
fileUploader.addEventListener('change', (e) => {
const file = e.target.files[0];
showPreview(file);
});

方法二:使用 createObjectURL

另一種常用的方法是使用 URL.createObjectURL() :

1
2
3
4
5
6
7
8
9
10
function showPreview(file) {
const preview = document.querySelector('#preview-img');
preview.src = URL.createObjectURL(file);

// 當圖片載入後,釋放記憶體
preview.onload = () => {
URL.revokeObjectURL(preview.src);
};
}

實用的檔案檢查功能

在實務上,我們常常需要檢查檔案是否符合要求:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 檢查檔案大小的函式
function formatFileSize(bytes) {
if (bytes < 1024) {
return bytes + ' bytes';
} else if (bytes < 1024 * 1024) {
return (bytes / 1024).toFixed(1) + ' KB';
} else {
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
}
}

// 檢查檔案是否符合規範
function validateFile(file) {
// 檢查大小(這裡設定 1MB 為上限)
if (file.size > 1024 * 1024) {
throw new Error(`檔案太大了!目前大小:${formatFileSize(file.size)}`);
}

// 檢查類型
const allowedTypes = ['image/jpeg', 'image/png'];
if (!allowedTypes.includes(file.type)) {
throw new Error('只能上傳 JPG 或 PNG 圖片!');
}
}

完整實例

以下是一個結合所有功能的完整範例:

HTML 部分:

1
2
3
4
5
6
<div class="upload-container">
<input type="file" id="file-uploader" accept="image/png, image/jpeg" />
<img id="preview-img" style="max-width: 200px; display: none;" />
<div id="error-message" style="color: red;"></div>
</div>

JavaScript 部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const fileUploader = document.querySelector('#file-uploader');
const previewImg = document.querySelector('#preview-img');
const errorMessage = document.querySelector('#error-message');

fileUploader.addEventListener('change', (e) => {
const file = e.target.files[0];
errorMessage.textContent = ''; // 清除錯誤訊息

try {
// 檢查檔案
validateFile(file);

// 顯示預覽
showPreview(file);
previewImg.style.display = 'block';

// 顯示檔案資訊
console.log(`已選擇檔案:${file.name}${formatFileSize(file.size)})`);

} catch (error) {
// 顯示錯誤訊息
errorMessage.textContent = error.message;
previewImg.style.display = 'none';
fileUploader.value = ''; // 清除已選擇的檔案
}
});

常見問題解決

實務上使用 Input File 時,可能會遇到一些問題,以下是常見問題及解決方法:

  1. 圖片預覽沒顯示
    • 檢查 img 元素的 CSS display 屬性
    • 確認 FileReader 的 onload 事件有被觸發
  2. 檔案大小限制不生效
    • 記得將檔案大小轉換為 bytes(1MB = 1024 * 1024 bytes)
    • 確認 validateFile 函式有被正確呼叫
  3. 上傳後想清除已選擇的檔案
    • 使用 fileUploader.value = '' 清除
    • 同時記得清除預覽圖片

用這樣的結構和內容,應該能幫助您更清楚地理解圖片上傳的處理流程。您有任何不清楚的地方嗎?

安全性考量

  1. 檔案類型驗證
    • 前後端都要驗證檔案類型
    • 不要只依賴副檔名,要檢查實際的 MIME type
    • 使用白名單方式限制允許的檔案類型
  2. 檔案大小限制
    • 設定合理的檔案大小上限
    • 在前端先進行驗證,避免無謂的上傳
    • 後端也要有檔案大小的限制
  3. 檔案存儲安全
    • 不要使用原始檔名儲存檔案
    • 產生隨機的檔案名稱
    • 確保儲存路徑不可被直接訪問
    • 考慮使用 CDN 或專業的檔案存儲服務

結語

Input File 雖然看似簡單,但實際操作起來確實存在不少小細節和潛在問題。我強烈建議大家親自動手實作一次,這樣真的能更深入理解其中的奧妙。要打造一個安全、實用且具有良好使用者體驗的檔案上傳功能,需要我們關注許多容易被忽略的細節。

希望透過這篇文章的分享,能幫助你在實際專案中更順利地實現檔案上傳功能,避開常見陷阱,打造出更好的使用者體驗。