# Vue File Uploader

一个支持 Vue 2.x 和 Vue 3.x 的文件上传组件，支持拖拽上传、多文件上传、进度显示等功能。

## 更新日志

### 1.4.0
- ✨ 优化文件上传性能
- 🔧 改进错误处理机制
- 🎨 优化组件样式和交互体验
- 📦 优化包体积
- 🐛 修复已知问题

### 1.3.0
- ✨ 优化 Vue 3 支持，移除不必要的 composition-api 依赖
- 🔧 改进类型定义，更好的 TypeScript 支持
- 📝 更新文档，添加 Vue 3 setup 语法糖示例
- 🐛 修复 Vue 3 环境下的类型导入问题
- 🎨 优化组件样式和交互体验
- 🚀 提升构建性能和包体积优化

### 1.2.0
- ✨ 新增 `clearFiles` 方法用于清空文件列表
- ✨ 新增 `tip` 插槽用于自定义提示信息
- ✨ 新增 `progress` 事件用于监听上传进度
- 🐛 修复 Vue 2.x 环境下的类型定义问题
- 🐛 修复文件大小限制的错误处理
- 📦 优化 ESM 和 CommonJS 模块导出
- 📝 完善 TypeScript 类型定义

### 1.0.0
- 🎯 初始版本发布
- ✨ 支持 Vue 2.x 和 Vue 3.x
- ✨ 支持点击和拖拽上传
- ✨ 支持单文件和多文件上传
- ✨ 支持文件类型和大小限制
- ✨ 支持自定义上传区域
- ✨ 支持上传进度显示
- 💪 使用 TypeScript 编写，提供完整的类型定义

## 特性

- 🎯 支持 Vue 2.x 和 Vue 3.x
- 🚀 支持点击和拖拽上传
- 📦 支持单文件和多文件上传
- 📊 实时显示上传进度
- 🎨 美观的 UI 和动画效果
- 🔧 高度可定制的界面
- 💪 使用 TypeScript 编写，提供完整的类型定义
- 📦 支持 ESM 和 CommonJS 两种模块规范

## 安装

### Vue 3.x
```bash
npm install @saberlayer/vue-file-uploader
```

### Vue 2.x
```bash
# Vue 2 环境需要同时安装 composition-api
npm install @saberlayer/vue-file-uploader @vue/composition-api
```

## 使用方法

### Vue 3.x

#### 1. 基础使用（Setup 语法糖）
```vue
<script setup lang="ts">
import { ref } from 'vue'
import { FileUploader } from '@saberlayer/vue-file-uploader'
import '@saberlayer/vue-file-uploader/dist/vue-file-uploader.css'

// 文件列表
const fileList = ref([])

// 文件状态改变
const handleChange = ({ file, fileList }) => {
  console.log('文件变化：', file, fileList)
}

// 上传成功
const handleSuccess = (file, fileList) => {
  console.log('上传成功：', file)
}

// 上传失败
const handleError = (error, file) => {
  console.error('上传失败：', error)
}

// 超出限制
const handleExceed = (files) => {
  console.warn('超出文件限制：', files)
}
</script>

<template>
  <FileUploader
    v-model:fileList="fileList"
    action="https://your-upload-url.com/upload"
    :multiple="true"
    :max-size="5 * 1024 * 1024"
    :max-count="5"
    accept=".jpg,.png,.pdf"
    :headers="{
      'Authorization': 'Bearer your-token'
    }"
    :data="{
      userId: 'user123',
      projectId: 'project456'
    }"
    @change="handleChange"
    @success="handleSuccess"
    @error="handleError"
    @exceed="handleExceed"
  />
</template>
```

#### 2. 手动上传模式
```vue
<script setup lang="ts">
import { ref } from 'vue'
import { FileUploader } from '@saberlayer/vue-file-uploader'
import '@saberlayer/vue-file-uploader/dist/vue-file-uploader.css'

const fileList = ref([])
const uploaderRef = ref()

// 手动上传
const handleUpload = () => {
  uploaderRef.value?.submit()
}

// 清空文件列表
const handleClear = () => {
  fileList.value = []
}
</script>

<template>
  <div>
    <FileUploader
      ref="uploaderRef"
      v-model:fileList="fileList"
      action="https://your-upload-url.com/upload"
      :auto-upload="false"
    />
    
    <div class="actions">
      <button @click="handleUpload">开始上传</button>
      <button @click="handleClear">清空列表</button>
    </div>
  </div>
</template>
```

### Vue 2.x

#### 1. 全局注册
```javascript
// main.js
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'
import { FileUploader } from '@saberlayer/vue-file-uploader'
import '@saberlayer/vue-file-uploader/dist/vue-file-uploader.css'

// 必须先安装 composition-api
Vue.use(VueCompositionAPI)
// 注册组件
Vue.component('FileUploader', FileUploader)
```

#### 2. 局部使用
```vue
<template>
  <div>
    <file-uploader
      :fileList="fileList"
      @update:fileList="handleFileListUpdate"
      action="https://your-upload-url.com/upload"
      :multiple="true"
      :max-size="5 * 1024 * 1024"
      :max-count="5"
      accept=".jpg,.png,.pdf"
      :headers="headers"
      :data="formData"
      @change="handleChange"
      @success="handleSuccess"
      @error="handleError"
      @exceed="handleExceed"
    >
      <!-- 自定义上传区域 -->
      <template #default>
        <div class="custom-upload">
          <p>点击或拖拽文件到此处上传</p>
          <p class="tip">支持 jpg、png、pdf 格式，单个文件不超过 5MB</p>
        </div>
      </template>
    </file-uploader>
  </div>
</template>

<script>
import { defineComponent, ref, reactive } from '@vue/composition-api'
import { FileUploader } from '@saberlayer/vue-file-uploader'
import '@saberlayer/vue-file-uploader/dist/vue-file-uploader.css'

export default defineComponent({
  components: {
    FileUploader
  },
  
  setup() {
    const fileList = ref([])
    
    const headers = reactive({
      'Authorization': 'Bearer your-token'
    })
    
    const formData = reactive({
      userId: 'user123',
      projectId: 'project456'
    })
    
    const handleFileListUpdate = (newFileList) => {
      fileList.value = newFileList
    }
    
    const handleChange = ({ file, fileList }) => {
      console.log('文件变化：', file, fileList)
    }
    
    const handleSuccess = (file, fileList) => {
      console.log('上传成功：', file)
    }
    
    const handleError = (error, file) => {
      console.error('上传失败：', error)
    }
    
    const handleExceed = (files) => {
      console.warn('超出文件限制：', files)
    }
    
    return {
      fileList,
      headers,
      formData,
      handleFileListUpdate,
      handleChange,
      handleSuccess,
      handleError,
      handleExceed
    }
  }
})
</script>

<style>
.custom-upload {
  padding: 24px;
  text-align: center;
}

.custom-upload .tip {
  margin-top: 8px;
  font-size: 14px;
  color: #666;
}
</style>
```

## API

### Props

| 参数 | 说明 | 类型 | 默认值 |
|------|------|------|--------|
| action | 上传的目标地址（必填） | string | - |
| fileList | 已上传的文件列表 | UploadFile[] | [] |
| multiple | 是否支持多文件上传 | boolean | false |
| accept | 接受的文件类型 | string | - |
| maxSize | 文件大小限制（字节） | number | 0 |
| maxCount | 文件数量限制 | number | 0 |
| headers | 上传请求头 | object | {} |
| data | 上传时附带的额外参数 | object | {} |
| autoUpload | 是否在选择文件后自动上传 | boolean | true |
| disabled | 是否禁用 | boolean | false |
| drag | 是否启用拖拽上传 | boolean | false |

### Events

| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| change | 文件状态改变时触发 | { file: UploadFile, fileList: UploadFile[] } |
| success | 文件上传成功时触发 | (file: UploadFile, fileList: UploadFile[]) |
| error | 文件上传失败时触发 | (error: Error, file: UploadFile) |
| progress | 文件上传进度变化时触发 | (file: UploadFile, percentage: number) |
| exceed | 文件数量超出限制时触发 | (files: File[]) |

### Methods

| 方法名 | 说明 | 参数 |
|--------|------|------|
| submit | 手动上传文件 | - |
| clearFiles | 清空文件列表 | - |

### Slots

| 插槽名 | 说明 |
|--------|------|
| default | 自定义上传区域的内容 |

### 类型定义

```typescript
interface UploadFile {
  uid: string;
  name: string;
  size: number;
  type: string;
  status: 'ready' | 'uploading' | 'success' | 'error';
  percentage?: number;
  response?: any;
  url?: string;
  error?: Error;
}
```

## 浏览器支持

- Chrome >= 51
- Firefox >= 53
- Safari >= 10
- Edge >= 79

## 开发

```bash
# 安装依赖
npm install

# 开发模式
npm run dev

# 构建 Vue 2.x 版本
npm run build:v2

# 构建 Vue 3.x 版本
npm run build:v3

# 构建所有版本
npm run build

# 运行示例
npm run demo

# 运行测试
npm run test
```

## 常见问题

### 1. Vue 2.x 环境下报错 "Composition API is not available"

确保已安装并注册 `@vue/composition-api`：

```javascript
import Vue from 'vue'
import VueCompositionAPI from '@vue/composition-api'

Vue.use(VueCompositionAPI)
```

### 2. 文件上传失败

检查以下几点：
- 上传地址 `action` 是否正确
- 服务器是否支持跨域请求
- 文件大小是否超出限制
- 网络连接是否正常

### 3. IE 11 兼容性问题

需要添加以下 polyfill：
- `core-js`
- `regenerator-runtime`

## License

MIT 