Skip to content

Upload

A complete file upload system built with Neo-Brutalism design, featuring drag-and-drop, file list management, progress tracking, and error handling.

Preview

Preview

基础 text 类型

点击或拖拽文件到此区域上传

document.pdf

1.47 MB

avatar.png

312.5 KB

picture 缩略图列表类型

点击或拖拽文件到此区域上传

sunset.jpg

sunset.jpg

2.34 MB

picture-card 照片墙类型(最大限制 3 张)

点击或拖拽文件到此区域上传

landscape.jpg

landscape.jpg

Installation

pnpm dlx brutx-vue@latest add upload

Usage

vue
<script setup>
import { ref } from 'vue'
import { Upload, UploadTrigger, UploadFileList, type UploadFile } from 'brutx-ui-vue'

const fileList = ref<UploadFile[]>([])

async function handleUpload(options) {
    // Custom upload implementation
    const formData = new FormData()
    formData.append('file', options.file)

    const response = await fetch('/api/upload', {
        method: 'POST',
        body: formData,
    })

    options.onSuccess(response)
}
</script>

<template>
    <Upload
        v-model:file-list="fileList"
        :http-request="handleUpload"
        accept="image/*"
        :max-size="5 * 1024 * 1024"
    >
        <template #trigger="{ selectFiles, drag }">
            <UploadTrigger :drag="drag" @select="selectFiles" />
        </template>
        <template #file-list="{ files, remove, retry }">
            <UploadFileList :files="files" @remove="remove" @retry="retry" />
        </template>
    </Upload>
</template>

Picture Card Type

vue
<script setup>
import { ref } from 'vue'
import { Upload, UploadTrigger, UploadFileList, type UploadFile } from 'brutx-ui-vue'

const fileList = ref<UploadFile[]>([])
</script>

<template>
    <Upload
        v-model:file-list="fileList"
        list-type="picture-card"
        :limit="5"
        multiple
    >
        <template #trigger="{ selectFiles }">
            <UploadTrigger @select="selectFiles" />
        </template>
        <template #file-list="{ files, remove }">
            <UploadFileList :files="files" list-type="picture-card" @remove="remove" />
        </template>
    </Upload>
</template>

With Hooks

vue
<script setup>
import { ref } from 'vue'
import { Upload, UploadTrigger, UploadFileList, type UploadFile } from 'brutx-ui-vue'

const fileList = ref<UploadFile[]>([])

function beforeUpload(file) {
    const isImage = file.type.startsWith('image/')
    if (!isImage) {
        console.error('只能上传图片文件!')
        return false
    }
    return true
}

async function beforeRemove(file) {
    return confirm(`确定删除 ${file.name} 吗?`)
}
</script>

<template>
    <Upload
        v-model:file-list="fileList"
        :before-upload="beforeUpload"
        :before-remove="beforeRemove"
    >
        <template #trigger="{ selectFiles }">
            <UploadTrigger @select="selectFiles" />
        </template>
        <template #file-list="{ files, remove }">
            <UploadFileList :files="files" @remove="remove" />
        </template>
    </Upload>
</template>

Sub-components

ComponentDescription
UploadRoot component, manages file list and upload logic
UploadTriggerTrigger area for file selection (drag/click)
UploadFileListFile list container
UploadFileItemSingle file item with preview, progress, and delete

Props

Upload

PropTypeDefaultDescription
fileListUploadFile[][]File list, supports v-model:fileList
limitnumberMaximum number of files
multiplebooleantrueWhether to support multiple file selection
acceptstringAccepted file types (e.g., image/*, .pdf,.doc)
maxSizenumberMaximum file size in bytes
maxRetriesnumber3Maximum retry count
beforeUpload(file: File) => boolean | Promise<boolean>Hook before upload
beforeRemove(file: UploadFile) => boolean | Promise<boolean>Hook before removal
httpRequest(options: UploadRequestOptions) => Promise<void>Custom upload implementation
listType'text' | 'picture' | 'picture-card''text'List display type
autoUploadbooleantrueWhether to upload automatically after selection
dragbooleantrueWhether to support drag and drop
onError(error: UploadError, file: UploadFile) => voidError callback
classstringCustom CSS class

UploadTrigger

PropTypeDefaultDescription
dragbooleantrueWhether to support drag and drop
disabledbooleanfalseWhether disabled
acceptstringAccepted file types
multiplebooleantrueWhether to support multiple selection
classstringCustom CSS class

UploadFileList

PropTypeDefaultDescription
filesUploadFile[]— (required)File list
listType'text' | 'picture' | 'picture-card''text'List display type
classstringCustom CSS class

Types

UploadFile

typescript
interface UploadFile {
    id: string
    name: string
    size: number
    type: string
    status: 'ready' | 'uploading' | 'success' | 'error'
    progress: number
    url?: string
    raw?: File
    error?: UploadError
}

UploadError

typescript
interface UploadError {
    message: string
    code?: string
    status?: number
}

UploadRequestOptions

typescript
interface UploadRequestOptions {
    file: File
    onProgress: (percent: number) => void
    onSuccess: (response: unknown) => void
    onError: (error: UploadError) => void
}

Events

Upload

EventPayloadDescription
update:fileListUploadFile[]Emitted when file list changes
file-changeUploadFileEmitted when a file is added
file-removeUploadFileEmitted when a file is removed
file-successUploadFileEmitted when a file is uploaded successfully
file-error[UploadFile, UploadError]Emitted when a file upload fails

UploadTrigger

EventPayloadDescription
selectFileListEmitted when files are selected

Exposed Methods

Upload

MethodDescription
handleFileSelect(files)Programmatically add files
handleFileRemove(file)Remove a file
retryUpload(file)Retry uploading a failed file

Slots

Upload

SlotScopeDescription
trigger{ selectFiles, limit, multiple, accept, drag }Trigger area slot
file-list{ files, listType, remove, retry }File list slot

UploadTrigger

SlotScopeDescription
default{ isDragging }Custom trigger content
textMain text
hintHint text

Accessibility

  • Keyboard: Trigger area is focusable and activatable with Enter / Space
  • ARIA Attributes: Hidden file input is properly labeled
  • Screen Readers: File status and progress are announced

Brute force builds.