Appearance
EstimatedProgressBar 预计进度条
说明
EstimatedProgressBar 是用于 Vue 3 异步任务的模拟进度条,适合文件导出、AI 生成、批量同步等无法获取真实完成比例的场景。调用 start() 后,进度先快后慢推进到 99%;业务任务成功后调用 finish() 补到 100%,失败或取消时调用 reset() 清理展示。
适用场景与边界
| 任务情况 | 建议处理 |
|---|---|
| 接口仅返回最终结果 | 开始任务时调用 start(),成功后调用一次 finish() |
| 已有上传字节数或后端真实进度 | 使用能够绑定真实百分比的进度组件 |
| 超时、失败或用户取消 | 由调用方处理请求状态,调用 reset() 并展示对应提示 |
| 多个任务同时执行 | 为各任务分别维护实例或由业务层汇总状态 |
显示的百分比是等待反馈,不代表服务端完成比例;durationSeconds 只控制模拟动画的预计时长,不会设置请求超时,也不会在时间到达后自动完成任务。
接入条件
组件只依赖 Vue。将 src/components/EstimatedProgressBar/index.vue 放入项目后直接导入即可;示例中的 @ 指向使用方的 src。text 是必传文案,默认预计时长为 28 秒,默认完成后保留展示。组件通过 ref 提供 start()、finish()、reset(),无需调用方维护显示开关。
实时预览
正在处理数据,请稍候...0%
当前预览进度:0%
组件内部会先快后慢推进到 99%,适合“真实任务未返回,但页面需要稳定反馈”的场景。
当外部任务完成后,只需要调用一次 finish(),组件会自动补到 100%。
源码位置
src/components/EstimatedProgressBar/index.vue
基本参数
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| text | string | - | 进度条上方的说明文案,通常用于提示当前任务状态。 |
| durationSeconds | number | 28 | 模拟进度推进到 99% 的预计时长,单位为秒。 |
| hideOnComplete | boolean | false | 完成后是否自动隐藏进度条。 |
暴露方法
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| start() | () => void | - | 开始模拟进度,按时长缓动推进到 99%。 |
| finish() | () => Promise<void> | - | 通知组件真实任务已完成,随后平滑补到 100%。 |
| reset() | () => void | - | 停止动画并重置为 0%,同时隐藏进度条。 |
事件
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| progress | (percent: number) => void | - | 进度变化时触发,适合在父组件里同步当前百分比文本。 |
基本使用方法
下面使用延时模拟异步任务,可在接入组件后直接运行。实际使用时把延时替换为业务请求,并确认请求成功后再调用 finish();如果使用 fetch,还需要检查响应的 ok 或业务状态码。
vue
<template>
<div class="task-progress">
<button type="button" :disabled="loading" @click="handleTask">
{{ loading ? '处理中…' : '开始任务' }}
</button>
<EstimatedProgressBar
ref="progressBarRef"
text="正在生成报告,请稍候..."
:duration-seconds="20"
/>
<p role="status">{{ taskMessage }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import EstimatedProgressBar from '@/components/EstimatedProgressBar/index.vue'
const progressBarRef = ref<InstanceType<typeof EstimatedProgressBar> | null>(null)
const loading = ref(false)
const taskMessage = ref('')
async function handleTask() {
if (loading.value || !progressBarRef.value) return
loading.value = true
taskMessage.value = '正在处理任务'
progressBarRef.value.start()
try {
await new Promise((resolve) => window.setTimeout(resolve, 5000))
await progressBarRef.value?.finish()
taskMessage.value = '任务已完成'
} catch (error) {
progressBarRef.value?.reset()
taskMessage.value = error instanceof Error ? error.message : '任务失败,请重试'
} finally {
loading.value = false
}
}
</script>代码示例
Estimated Progress Bar 基础示例点击展开
<template>
<div class="task-progress">
<el-button type="primary" @click="handleTask">开始任务</el-button>
<EstimatedProgressBar
ref="progressBarRef"
text="正在生成报告,请稍候..."
:duration-seconds="20"
@progress="currentPercent = $event"
/>
<div class="task-progress__meta">当前进度:{{ Math.round(currentPercent) }}%</div>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import EstimatedProgressBar from '@/components/EstimatedProgressBar/index.vue'
const progressBarRef = ref<any>(null)
const currentPercent = ref(0)
const handleTask = async () => {
progressBarRef.value?.start()
try {
await new Promise((resolve) => window.setTimeout(resolve, 5000))
await progressBarRef.value?.finish()
} catch (error) {
progressBarRef.value?.reset()
}
}
</script>
<style scoped>
.task-progress {
display: grid;
gap: 12px;
}
.task-progress__meta {
font-size: 13px;
color: #6b7280;
}
</style>常见问题
为什么进度停在 99%?
这是组件的预期行为。模拟时长结束后仍然等待真实任务结果,只有调用方调用 finish() 才会推进到 100%。请检查业务成功分支是否调用了该方法。
请求失败或取消时怎么处理?
调用 reset() 停止动画、隐藏进度条并把进度恢复到 0,同时在业务界面展示失败或取消提示。reset() 只管理组件状态,不会取消网络请求;使用可取消请求时,调用方还需取消请求,并避免旧请求结束后再次调用 finish()。
finish() 返回的 Promise 表示什么?
它用于等待补齐进度的动画结束,不代表业务请求完成。组件在 start() 重新开始、reset() 或卸载时也会结束正在等待的完成 Promise,因此业务成功状态必须以请求结果为准。启用 hideOnComplete 后,完成动画结束还会短暂保留再隐藏。
可以重复点击开始或完成吗?
start() 会重置进度并重新开始。调用方应在任务期间禁用重复提交,并在成功分支只调用一次 finish(),避免多次完成动画互相覆盖。
相关文档
- QyqForm 动态表单:收集任务参数并在提交前校验。
- QyqTable 数据表格:展示任务列表或处理结果。
- 组件目录:按业务场景选择组件。