Tìm hiểu sâu về component tải file - el-upload

Giới thiệu

Trong bài viết này, chúng ta sẽ cùng phân tích chi tiết component el-upload của Element Plus. Trước tiên, hãy xem qua một ví dụ cơ bản từ tài liệu chính thức:
<template>
  <el-upload
    v-model:file-list="fileList"
    class="upload-demo"
    action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
    multiple
    :on-preview="handlePreview"
    :on-remove="handleRemove"
    :before-remove="beforeRemove"
    :limit="3"
    :on-exceed="handleExceed"
  >
    <el-button type="primary">Click to upload</el-button>
    <template #tip>
      <div class="el-upload__tip">
        jpg/png files with a size less than 500KB.
      </div>
    </template>
  </el-upload>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
import { ElMessage, ElMessageBox } from 'element-plus'

import type { UploadProps, UploadUserFile } from 'element-plus'

const fileList = ref<UploadUserFile[]>([
  {
    name: 'element-plus-logo.svg',
    url: 'https://element-plus.org/images/element-plus-logo.svg',
  },
  {
    name: 'element-plus-logo2.svg',
    url: 'https://element-plus.org/images/element-plus-logo.svg',
  },
])

const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  console.log(file, uploadFiles)
}

const handlePreview: UploadProps['onPreview'] = (uploadFile) => {
  console.log(uploadFile)
}

const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
  ElMessage.warning(
    `The limit is 3, you selected ${files.length} files this time, add up to ${
      files.length + uploadFiles.length
    } totally`
  )
}

const beforeRemove: UploadProps['beforeRemove'] = (uploadFile, uploadFiles) => {
  return ElMessageBox.confirm(
    `Cancel the transfer of ${uploadFile.name} ?`
  ).then(
    () => true,
    () => false
  )
}
</script>

Các type quan trọng

Chúng ta cùng xem chi tiết hai type quan trọng được import vào:
// UploadProps chứa tất cả các thuộc tính của component Upload
type UploadProps = {
  action: string // Địa chỉ upload
  headers?: Headers | Record<string, any> // Header của request
  method?: string // Phương thức upload, mặc định là post
  multiple?: boolean // Cho phép chọn nhiều file
  data?: Record<string, any> // Tham số bổ sung khi upload
  name?: string // Tên trường file, mặc định là file
  withCredentials?: boolean // Gửi cookie cùng request
  showFileList?: boolean // Hiển thị danh sách file đã upload
  drag?: boolean // Bật tính năng kéo thả
  accept?: string // Loại file được chấp nhận
  fileList?: UploadUserFile[] // Danh sách file
  listType?: 'text' | 'picture' | 'picture-card' // Kiểu hiển thị danh sách
  autoUpload?: boolean // Upload tự động
  disabled?: boolean // Vô hiệu hóa component
  limit?: number // Số file tối đa được phép upload
}

// UploadUserFile định nghĩa cấu trúc dữ liệu của một file
interface UploadUserFile {
  name: string // Tên file
  url?: string // Đường dẫn file
  uid: number | string // ID duy nhất của file
  status?: 'ready' | 'uploading' | 'success' | 'fail' // Trạng thái file
  size?: number // Kích thước file
  raw?: File // Đối tượng File gốc
  response?: any // Phản hồi từ server
  percentage?: number // Tiến trình upload
}

Về cú pháp TypeScript

Đoạn code này sử dụng cú pháp indexed access types trong TypeScript:
const handleRemove: UploadProps['onRemove'] = (file, uploadFiles) => {
  console.log(file, uploadFiles)
}
Cú pháp UploadProps['onRemove'] cho phép truy xuất type của thuộc tính onRemove từ interface UploadProps. Điều này có nghĩa là handleRemove được định nghĩa như một hàm nhận vào hai tham số: file là file được thao tác và uploadFiles là mảng tất cả các file hiện tại.

Cách thức hoạt động

Khi sử dụng el-upload, quy trình diễn ra như sau: 1. Người dùng click vào button được bọc trong el-upload 2. Component kích hoạt một input file ẩn 3. Các hook được gọi theo thứ tự: before-uploadon-changeon-progresson-success / on-erroron-exceed (nếu vượt quá limit) Lưu ý quan trọng: Component sử dụng axios làm phương thức gửi request mặc định. Thuộc tính action là bắt buộc và mặc định sử dụng method POST. Nếu muốn tự xử lý hoàn toàn logic upload, bạn có thể đặt action="#" và viết logic trong các hook tương ứng.

Upload bằng kéo thả và thủ công

**Upload kéo thả (Drag & Drop):** Bật thuộc tính drag để kích hoạt tính năng này. Component sẽ lắng nghe các sự kiện kéo thả từ trình duyệt. **Upload thủ công:** Đặt :auto-upload="false" để tắt upload tự động. Sau đó gọi phương thức submit() thông qua ref khi cần thiết:
const uploadRef = ref()
uploadRef.value!.submit()

Kết luận

Việc sử dụng el-upload khá đơn giản. Chỉ cần bọc một button trong component, thiết lập thuộc tính action trỏ đến URL backend, và xử lý các sự kiện thông qua các hook được cung cấp. Component sẽ tự động xử lý phần gửi request và quản lý trạng thái file.

Đăng vào ngày 6 tháng 7 lúc 22:37