keke-alioss-upload-vue
v1.1.0
Published
一个基于 Vue 3 和阿里云 OSS 的高性能文件上传组件,支持断点续传、分片上传、多文件上传等功能。
Maintainers
Readme
keke-ali-oss-vue
一个基于 Vue 3 和阿里云 OSS 的高性能文件上传组件,支持断点续传、分片上传、多文件上传等功能。
✨ 特性
- 🚀 断点续传:支持上传中断后继续上传,无需重新开始
- 📦 分片上传:大文件自动分片上传,提高上传效率
- 🔄 并发控制:支持多文件并发上传(默认最多 2 个文件同时上传)
- 📊 进度追踪:实时显示上传进度
- 🔐 STS Token 自动刷新:自动检测并刷新过期的临时凭证
- ✅ 文件校验:支持上传前文件类型、大小等校验
- 🎯 TypeScript 支持:完整的 TypeScript 类型定义
- 🎨 灵活定制:支持自定义上传按钮和样式
📦 安装
npm install keke-ali-oss-vue
# 或
yarn add keke-ali-oss-vue
# 或
pnpm add keke-ali-oss-vue🔧 依赖要求
- Vue 3.0+
- ali-oss 6.0+
🚀 快速开始
基础用法
<template>
<OssUpload
:getUploadToken="getUploadToken"
@uploadFinish="handleUploadFinish"
/>
</template>
<script setup lang="ts">
import OssUpload from 'keke-ali-oss-vue';
import type { OssUploadParams } from 'keke-ali-oss-vue';
const getUploadToken = async (): Promise<OssUploadParams> => {
// 调用后端接口获取 STS Token
const response = await fetch('/api/getStsToken');
const data = await response.json();
return {
options: {
bucket: data.bucket,
endpoint: data.endpoint,
accessKeyId: data.accessKeyId,
accessKeySecret: data.accessKeySecret,
stsToken: data.securityToken,
},
ossUploadLimit: {
filePath: data.ossObjectPath,
defaultUrl: data.cdnProtocolDomainInfo,
expiredDuration: data.expiredDuration, // 单位:秒
},
};
};
const handleUploadFinish = (taskList: any[], urls: string[], failedFiles: any[]) => {
console.log('上传完成', urls);
};
</script>通过 ref 调用上传
<template>
<div>
<button @click="ossUploadRef?.activeUpload()">点击上传</button>
<span v-if="ossUploadRef?.loading">上传中...</span>
<span>上传进度:{{ ossUploadRef?.uploadProgressVal }}%</span>
<OssUpload
ref="ossUploadRef"
:getUploadToken="getUploadToken"
@uploadFinish="handleUploadFinish"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import OssUpload from 'keke-ali-oss-vue';
import type { OssUploadParams } from 'keke-ali-oss-vue';
const ossUploadRef = ref('ossUploadRef');
const getUploadToken = async (): Promise<OssUploadParams> => {
// ... 获取 token 的逻辑
};
const handleUploadFinish = (taskList: any[], urls: string[], failedFiles: any[]) => {
console.log('上传完成', urls);
};
</script>📖 API 文档
Props 参数
| 参数 | 说明 | 类型 | 必填 | 默认值 |
|------|------|------|------|--------|
| getUploadToken | 获取 STS Token 的函数 | () => Promise<OssUploadParams> | 是 | - |
| multiple | 是否支持多选 | boolean | 否 | false |
| limit | 限制上传数量(仅在 multiple 为 true 时生效) | number | 否 | undefined |
| accept | 限制上传的文件类型,多个类型用逗号分隔,如:.jpg,.png,.pdf | string | 否 | '*' |
| disabled | 是否禁用 | boolean | 否 | false |
| beforeEachUpload | 单个文件上传前的校验钩子,返回 false 则不上传该文件 | (file: File) => Promise<boolean> | 否 | undefined |
| beforeUpload | 批量上传前的校验钩子,返回 false 则不进行上传 | (files: File[]) => Promise<boolean> | 否 | undefined |
Events 事件
| 事件名 | 说明 | 回调参数 |
|--------|------|----------|
| uploadFinish | 所有文件上传完成时触发 | (taskList: TaskItem[], urls: string[], failedFiles: FailedFileMsg[]) |
| exceed | 超出上传数量限制时触发 | (files: File[]) |
| eachUploadFinish | 单个文件上传完成时触发 | (task: TaskItem, url: string) |
暴露的方法和属性
通过 ref 可以访问以下方法和属性:
| 方法/属性 | 说明 | 类型 |
|-----------|------|------|
| uploadFiles | 手动触发文件上传 | (files: File[]) => Promise<void> |
| activeUpload | 激活文件选择对话框 | () => void |
| uploadProgressVal | 上传进度百分比(0-100) | number |
| loading | 是否正在上传 | boolean |
类型定义
interface OssUploadParams {
options: {
bucket: string; // OSS Bucket 名称
endpoint: string; // OSS 地域域名
accessKeyId: string; // 临时访问密钥 ID
accessKeySecret: string; // 临时访问密钥 Secret
stsToken: string; // STS Token
};
ossUploadLimit: {
filePath: string; // OSS 文件路径前缀
defaultUrl: string; // CDN 访问域名
expiredDuration: number; // Token 过期时长(秒)
};
}
interface TaskItem {
uid: string;
file: RcFile;
fileName: string;
fileType: string;
fileSize: number;
uploadStatus: 'waiting' | 'uploading' | 'fail' | 'success';
ossUrl: string;
progress: number;
failReason?: '' | 'formatError';
// ... 更多属性
}
interface FailedFileMsg {
file: File;
failReason?: string;
status: string;
}💡 使用示例
示例 1:限制文件类型和数量
<template>
<OssUpload
:getUploadToken="getUploadToken"
:multiple="true"
:limit="5"
accept=".jpg,.jpeg,.png,.webp"
@uploadFinish="handleUploadFinish"
@exceed="handleExceed"
/>
</template>
<script setup lang="ts">
import OssUpload from 'keke-ali-oss-vue';
import type { OssUploadParams } from 'keke-ali-oss-vue';
const handleUploadFinish = (taskList: any[], urls: string[], failedFiles: any[]) => {
if (failedFiles.length > 0) {
console.warn('部分文件上传失败', failedFiles);
}
console.log('成功上传的文件 URL:', urls);
};
const handleExceed = (files: File[]) => {
console.warn('超出上传数量限制', files);
// 可以在这里显示提示信息
};
</script>示例 2:上传前校验文件大小
<template>
<OssUpload
:getUploadToken="getUploadToken"
:beforeEachUpload="validateFile"
@uploadFinish="handleUploadFinish"
/>
</template>
<script setup lang="ts">
import OssUpload from 'keke-ali-oss-vue';
const validateFile = async (file: File): Promise<boolean> => {
// 限制文件大小为 10MB
const maxSize = 10 * 1024 * 1024;
if (file.size > maxSize) {
alert('文件大小不能超过 10MB');
return false;
}
return true;
};
</script>示例 3:批量上传前校验
<template>
<OssUpload
:getUploadToken="getUploadToken"
:multiple="true"
:beforeUpload="validateFiles"
@uploadFinish="handleUploadFinish"
/>
</template>
<script setup lang="ts">
import OssUpload from 'keke-ali-oss-vue';
const validateFiles = async (files: File[]): Promise<boolean> => {
// 检查总文件大小
const totalSize = files.reduce((sum, file) => sum + file.size, 0);
const maxTotalSize = 100 * 1024 * 1024; // 100MB
if (totalSize > maxTotalSize) {
alert('总文件大小不能超过 100MB');
return false;
}
return true;
};
</script>示例 4:监听单个文件上传完成
<template>
<OssUpload
:getUploadToken="getUploadToken"
:multiple="true"
@eachUploadFinish="handleEachUploadFinish"
@uploadFinish="handleUploadFinish"
/>
</template>
<script setup lang="ts">
import OssUpload from 'keke-ali-oss-vue';
const handleEachUploadFinish = (task: any, url: string) => {
console.log(`文件 ${task.fileName} 上传完成,URL: ${url}`);
// 可以在这里更新 UI,显示每个文件的上传状态
};
const handleUploadFinish = (taskList: any[], urls: string[], failedFiles: any[]) => {
console.log('所有文件上传完成');
};
</script>示例 5:完整示例(包含进度显示)
<template>
<div class="upload-container">
<button
@click="ossUploadRef?.activeUpload()"
:disabled="ossUploadRef?.loading"
>
{{ ossUploadRef?.loading ? '上传中...' : '选择文件' }}
</button>
<div v-if="ossUploadRef?.loading" class="progress">
<div class="progress-bar" :style="{ width: `${ossUploadRef?.uploadProgressVal}%` }"></div>
<span class="progress-text">{{ ossUploadRef?.uploadProgressVal }}%</span>
</div>
<div v-if="previewUrl" class="preview">
<img :src="previewUrl" alt="预览图" />
</div>
<OssUpload
ref="ossUploadRef"
:getUploadToken="getUploadToken"
accept=".jpg,.jpeg,.png,.webp"
@uploadFinish="handleUploadFinish"
/>
</div>
</template>
<script setup lang="ts">
import { ref, ref } from 'vue';
import OssUpload from 'keke-ali-oss-vue';
import type { OssUploadParams } from 'keke-ali-oss-vue';
const ossUploadRef = ref('ossUploadRef');
const previewUrl = ref('');
const getUploadToken = async (): Promise<OssUploadParams> => {
// 从后端获取 STS Token
const response = await fetch('/api/getStsToken');
const data = await response.json();
return {
options: {
bucket: data.bucket,
endpoint: data.endpoint,
accessKeyId: data.accessKeyId,
accessKeySecret: data.accessKeySecret,
stsToken: data.securityToken,
},
ossUploadLimit: {
filePath: data.ossObjectPath,
defaultUrl: data.cdnProtocolDomainInfo,
expiredDuration: data.expiredDuration,
},
};
};
const handleUploadFinish = (taskList: any[], urls: string[], failedFiles: any[]) => {
if (urls.length > 0) {
previewUrl.value = urls[0];
}
if (failedFiles.length > 0) {
console.error('上传失败的文件:', failedFiles);
}
};
</script>
<style scoped>
.upload-container {
display: flex;
flex-direction: column;
gap: 10px;
}
.progress {
position: relative;
width: 100%;
height: 20px;
background-color: #f0f0f0;
border-radius: 4px;
overflow: hidden;
}
.progress-bar {
height: 100%;
background-color: #409eff;
transition: width 0.3s;
}
.progress-text {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 12px;
}
.preview img {
max-width: 300px;
height: auto;
}
</style>⚙️ 配置说明
getUploadToken 返回值
getUploadToken 函数必须返回 OssUploadParams 类型的对象,包含以下字段:
options: OSS 客户端配置
bucket: OSS Bucket 名称endpoint: OSS 地域域名(如:oss-cn-hangzhou.aliyuncs.com)accessKeyId: 临时访问密钥 IDaccessKeySecret: 临时访问密钥 SecretstsToken: STS Token
ossUploadLimit: 上传限制配置
filePath: OSS 文件路径前缀(如:uploads/images/)defaultUrl: CDN 访问域名(如:https://cdn.example.com)expiredDuration: Token 过期时长(单位:秒)
📝 注意事项
STS Token 获取:
getUploadToken函数必须返回正确的OssUploadParams格式,包含完整的 OSS 配置信息。文件类型限制:
accept参数支持标准的 HTML input accept 格式,如.jpg,.png或image/*。并发上传:组件内部支持最大 2 个文件并发上传,每个文件使用 5 个分片并发上传。
断点续传:组件支持断点续传功能,上传失败后可以继续上传。
Token 刷新:组件会自动检测 Token 是否过期(有效期不足 1 分钟时视为过期),并自动刷新。
文件命名:上传的文件会自动重命名为
{uid}_{timestamp}.{ext}格式,避免文件名冲突。分片大小:默认分片大小为 10MB,适合大多数场景。
🔍 常见问题
Q: 如何自定义上传按钮样式?
A: 组件本身只包含一个隐藏的 input 元素,你可以通过 ref 调用 activeUpload() 方法,然后自定义按钮样式。
Q: 如何获取上传进度?
A: 通过 ref 访问 uploadProgressVal 属性,它是一个 0-100 的数值,表示整体上传进度。
Q: 上传失败后如何重试?
A: 组件会在 uploadFinish 事件的 failedFiles 参数中返回失败的文件信息,你可以根据这些信息重新调用 uploadFiles 方法进行重试。
Q: 如何限制文件大小?
A: 使用 beforeEachUpload 或 beforeUpload 钩子函数进行文件大小校验,返回 false 即可阻止上传。
Q: 支持哪些文件类型?
A: 通过 accept 属性可以限制文件类型,支持所有标准的 MIME 类型和文件扩展名。
📄 类型导入
如果需要使用 TypeScript 类型,可以按以下方式导入:
import type {
TaskItem,
OssUploadParams,
RcFile,
FailedFileMsg
} from 'keke-ali-oss-vue';🤝 贡献
欢迎提交 Issue 和 Pull Request!
📜 许可证
MIT
