Skip to content

Upload 上传

文件选择上传和拖拽上传组件。

基础用法

最简单的上传组件用法。

vue
<template>
  <ex-upload
    action="/api/upload"
    :on-success="handleSuccess"
    :on-error="handleError"
  >
    <ex-button type="primary">
      <ex-icon name="upload" />
      选择文件
    </ex-button>
  </ex-upload>
</template>

<script setup>
const handleSuccess = (response, file, fileList) => {
  console.log('上传成功:', response)
}

const handleError = (error, file, fileList) => {
  console.error('上传失败:', error)
}
</script>

拖拽上传

支持拖拽文件到指定区域进行上传。

vue
<template>
  <ex-upload
    action="/api/upload"
    drag
    :on-success="handleSuccess"
  >
    <div class="upload-dragger">
      <ex-icon name="upload" style="font-size: 48px; color: #999;" />
      <div>将文件拖到此处,或<em>点击上传</em></div>
    </div>
  </ex-upload>
</template>

<script setup>
const handleSuccess = (response, file, fileList) => {
  console.log('上传成功:', response)
}
</script>

文件列表

显示已选择的文件列表,支持不同的展示样式。

vue
<template>
  <div>
    <h4>文本列表</h4>
    <ex-upload
      action="/api/upload"
      list-type="text"
      :file-list="fileList1"
      @update:file-list="fileList1 = $event"
    >
      <ex-button>选择文件</ex-button>
    </ex-upload>

    <h4>图片列表</h4>
    <ex-upload
      action="/api/upload"
      list-type="picture"
      :file-list="fileList2"
      @update:file-list="fileList2 = $event"
    >
      <ex-button>选择图片</ex-button>
    </ex-upload>

    <h4>卡片列表</h4>
    <ex-upload
      action="/api/upload"
      list-type="picture-card"
      :file-list="fileList3"
      @update:file-list="fileList3 = $event"
    >
      <div class="upload-card">
        <ex-icon name="plus" />
        <div>上传</div>
      </div>
    </ex-upload>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const fileList1 = ref([])
const fileList2 = ref([])
const fileList3 = ref([])
</script>

文件限制

限制上传文件的类型、大小和数量。

vue
<template>
  <div>
    <h4>限制文件类型</h4>
    <ex-upload
      action="/api/upload"
      accept="image/*"
      :on-exceed="handleExceed"
    >
      <ex-button>只能上传图片</ex-button>
    </ex-upload>

    <h4>限制文件大小</h4>
    <ex-upload
      action="/api/upload"
      :max-size="1024 * 1024"
      :before-upload="beforeUpload"
    >
      <ex-button>文件大小不超过1MB</ex-button>
    </ex-upload>

    <h4>限制文件数量</h4>
    <ex-upload
      action="/api/upload"
      :max-count="3"
      multiple
      :on-exceed="handleExceed"
    >
      <ex-button>最多上传3个文件</ex-button>
    </ex-upload>
  </div>
</template>

<script setup>
const handleExceed = (files, fileList) => {
  console.warn('文件数量超出限制')
}

const beforeUpload = (file) => {
  const isLt1M = file.size / 1024 / 1024 < 1
  if (!isLt1M) {
    console.error('文件大小不能超过 1MB!')
    return false
  }
  return true
}
</script>

手动上传

关闭自动上传,手动控制上传时机。

vue
<template>
  <div>
    <ex-upload
      ref="uploadRef"
      action="/api/upload"
      :auto-upload="false"
      multiple
      :on-change="handleChange"
    >
      <ex-button>选择文件</ex-button>
    </ex-upload>
    
    <div style="margin-top: 16px;">
      <ex-button type="primary" @click="submitUpload">上传到服务器</ex-button>
      <ex-button @click="clearFiles">清空文件</ex-button>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const uploadRef = ref()

const handleChange = (info) => {
  console.log('文件列表变化:', info.fileList)
}

const submitUpload = () => {
  uploadRef.value.submit()
}

const clearFiles = () => {
  uploadRef.value.clearFiles()
}
</script>

自定义上传

使用自定义的上传实现。

vue
<template>
  <ex-upload
    :custom-request="customUpload"
    :show-file-list="false"
  >
    <ex-button :loading="uploading">
      {{ uploading ? '上传中...' : '自定义上传' }}
    </ex-button>
  </ex-upload>
</template>

<script setup>
import { ref } from 'vue'

const uploading = ref(false)

const customUpload = async (option) => {
  uploading.value = true
  
  try {
    const formData = new FormData()
    formData.append('file', option.file)
    
    const response = await fetch('/api/custom-upload', {
      method: 'POST',
      body: formData,
      onUploadProgress: (progressEvent) => {
        const percent = Math.round(
          (progressEvent.loaded * 100) / progressEvent.total
        )
        option.onProgress({ percent })
      }
    })
    
    const result = await response.json()
    option.onSuccess(result)
  } catch (error) {
    option.onError(error)
  } finally {
    uploading.value = false
  }
}
</script>

图片预览

支持图片文件的预览功能。

vue
<template>
  <ex-upload
    action="/api/upload"
    list-type="picture-card"
    :on-preview="handlePreview"
    :file-list="fileList"
    @update:file-list="fileList = $event"
  >
    <div class="upload-card">
      <ex-icon name="plus" />
      <div>上传</div>
    </div>
  </ex-upload>
</template>

<script setup>
import { ref } from 'vue'

const fileList = ref([
  {
    uid: '1',
    name: 'image1.png',
    status: 'success',
    url: 'https://example.com/image1.png'
  },
  {
    uid: '2',
    name: 'image2.jpg',
    status: 'success',
    url: 'https://example.com/image2.jpg'
  }
])

const handlePreview = (file) => {
  console.log('预览文件:', file)
  // 可以在这里实现自定义预览逻辑
}
</script>

上传进度

显示文件上传进度。

vue
<template>
  <ex-upload
    action="/api/upload"
    :on-progress="handleProgress"
    :on-success="handleSuccess"
    :on-error="handleError"
  >
    <ex-button>上传文件</ex-button>
  </ex-upload>
</template>

<script setup>
const handleProgress = (event, file, fileList) => {
  console.log(`上传进度: ${event.percent}%`)
}

const handleSuccess = (response, file, fileList) => {
  console.log('上传成功:', file.name)
}

const handleError = (error, file, fileList) => {
  console.error('上传失败:', file.name, error)
}
</script>

API

Props

参数说明类型默认值
action上传的地址string''
method上传请求的方法string'post'
name上传的文件字段名string'file'
data上传时附带的额外参数object{}
headers设置上传的请求头部object{}
withCredentials支持发送 cookie 凭证信息booleanfalse
multiple是否支持多选文件booleanfalse
accept接受上传的文件类型string''
maxSize限制文件大小(字节)numberundefined
maxCount限制文件数量numberundefined
drag是否启用拖拽上传booleanfalse
disabled是否禁用booleanfalse
autoUpload是否自动上传booleantrue
showFileList是否显示文件列表booleantrue
listType文件列表的类型'text' | 'picture' | 'picture-card''text'
fileList文件列表UploadFile[][]
size组件大小'small' | 'medium' | 'large''medium'
buttonType按钮类型'primary' | 'secondary' | 'success' | 'warning' | 'danger''primary'
buttonText按钮文本stringundefined
tip提示文本stringundefined
showTip是否显示提示booleantrue

Events

事件名说明参数
update:fileList文件列表更新时触发(fileList: UploadFile[])
change文件状态改变时触发(param: UploadChangeParam)
beforeUpload文件上传前的钩子(file: File, fileList: UploadFile[])
progress文件上传进度(event: UploadProgressEvent, file: UploadFile, fileList: UploadFile[])
success文件上传成功时触发(response: any, file: UploadFile, fileList: UploadFile[])
error文件上传失败时触发(error: Error, file: UploadFile, fileList: UploadFile[])
preview点击文件预览时触发(file: UploadFile)
remove文件移除时触发(file: UploadFile, fileList: UploadFile[])
download点击下载文件时触发(file: UploadFile)
exceed文件超出数量限制时触发(files: File[], fileList: UploadFile[])

Methods

方法名说明参数
submit手动上传文件列表()
clearFiles清空文件列表()
abort取消上传请求(file?: UploadFile)

Slots

插槽名说明参数
default默认插槽,上传按钮内容{ click: Function }
trigger触发上传的元素{ click: Function }
tip提示信息{}

Types

typescript
interface UploadFile {
  uid: string
  name: string
  size?: number
  type?: string
  status: 'ready' | 'uploading' | 'success' | 'error'
  percent?: number
  url?: string
  thumbUrl?: string
  response?: any
  error?: any
  originFileObj?: File
}

interface UploadProgressEvent {
  percent: number
  loaded: number
  total: number
}

interface UploadChangeParam {
  file: UploadFile
  fileList: UploadFile[]
}

interface UploadRequestOption {
  action?: string
  filename: string
  file: File
  data?: Record<string, any>
  headers?: Record<string, string>
  withCredentials?: boolean
  onProgress?: (event: UploadProgressEvent) => void
  onSuccess?: (response: any) => void
  onError?: (error: Error) => void
}

样式变量

组件提供了以下CSS变量用于自定义样式:

css
:root {
  --ex-upload-drag-border-color: var(--ex-border-color);
  --ex-upload-drag-bg-color: var(--ex-bg-color-page);
  --ex-upload-drag-hover-border-color: var(--ex-color-primary);
  --ex-upload-drag-hover-bg-color: var(--ex-color-primary-light-9);
  --ex-upload-list-item-hover-bg: var(--ex-bg-color-page);
  --ex-upload-progress-bg: var(--ex-color-primary);
}