0%

Angular 筆記 - 檔案上傳實作

upload

主要需求

需要一個上傳檔案的功能,但為了視覺統一,要把真正上傳檔案的部分隱藏,用另一個 input 來呈現上傳檔案的內容。

建立上傳檔案區塊

1
2
3
4
5
<div class="uploadFileBlock">
<input type="file" class="uploadInput" />
<input type="text" />
<button class="btn">檔案上傳</button>
</div>
  1. 建立一個上傳檔案的區塊(可以看實際專案需求),裡面個別放了兩個 input。
  2. 第一個 input 的 type 是 file,主要用來上傳檔案用的。
  3. 第二個 input 的 type 是 text,是用來呈現上傳檔案的檔名。
  4. 使用按鈕完成上傳檔案的功能。

完成主要架構後先來進行樣式的處理。

CSS 樣式

因為只會出現一個 input,並且前端介面要給使用者看到的是上傳檔案的檔名結果,所以我把 .uploadInput 使用 display:none 隱藏起來,之後要用 Angular 的範本變數去觸發這個功能。

HTML

1
2
3
4
5
<div class="uploadFileBlock">
<input type="file" class="uploadInput" />
<input type="text" class="viewInput" />
<button class="btn">檔案上傳</button>
</div>

此練習有使用到 Tailwind CSS 作樣式,基本上沒有很困難,可以參考樣式內容。

SCSS

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.uploadFileBlock {
@apply mb-5;
}

.uploadInput {
display: none;
}

.viewInput {
@apply py-2 px-1 rounded-md border-gray-400 border-2 focus:ring-2 focus:border-gray-400;
outline: none;
}

.btn {
@apply text-white bg-green-500 py-2 px-4 ml-2 hover:bg-green-600 duration-200;
}

使用範本變數取得 click 事件的值

透過自定義的範本變數可以讓按鈕取得 input 裡面的值。

HTML

1
2
3
4
5
6
7
8
9
10
<div class="uploadFileBlock">
<input
type="file"
class="uploadInput"
(change)="fileSelected($event)"
#fileUpload
/>
<input type="text" class="viewInput" />
<button class="btn" (click)="fileUpload.click()">檔案上傳</button>
</div>
  1. 在第一個 input 給一個 change 事件以及範本變數,這邊自定義為 #fileUpload,前面要加井字號,這樣就完成了範本變數的綁定。
  2. 再來在第二個按鈕上新增 click 事件,去取得範本變數 fileUpload 的 click 方法。

此時 ts 檔也要同時新增 change 事件方法。

TypeScript

1
2
3
fileSelected(e) {
console.log(e);
}

在點擊按鈕後會彈跳出一個視窗,需要先選擇檔案,可以任意選擇一個檔案試試看,選擇後在 console 就可以看到有事件的內容出現。

console

然後可以找到一個 target 的屬性,再找到 files 這個屬性,在點開會發現是一個陣列,裡面有一個物件。

target

取得 file 的內容

此時可以在 fileSelected 方法中寫入功能,這邊假設我要取得檔案的名稱。

TypeScript

1
2
3
4
5
6
7
8
9
10
fileName: string;
fileSelected(e) {
console.log(e);
const file: File = e.target.files[0];
if (file) {
this.fileName = file.name;
const formData = new FormData();
formData.append('thumbnail', file);
}
}
  1. 從 console 中可以知道 files 裡面只有一個物件,所以我取得第 0 筆資料。
  2. 判斷如果 file 是 true 的時候,宣告一個 fileName 去儲存 file.name 的檔案名稱。
  3. 因為來源是不可改變的,所以我用 const 宣告一個變數 formData,並 new 一個 formData 的實體。
  4. 在使用 append 方法去增加檔案。

把檔名放到前端顯示

剛剛已經透過全域變數取得 file.name 的字串,我在第二個 input 綁定一個 placeholder,並用三元運算子判斷要顯示變數內容或是預設提示文字。

HTML

1
2
3
4
5
<input
type="text"
class="viewInput"
[placeholder]="fileName ? fileName : '請上傳檔案'"
/>

這樣就完成了,

DEMO: https://stackblitz.com/edit/angular-ivy-cfj62u?embed=1&file=src/app/app.component.html

參考資料