Skip to content

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%

组件内部会先快后慢推进到 99%,适合“真实任务未返回,但页面需要稳定反馈”的场景。

当外部任务完成后,只需要调用一次 finish(),组件会自动补到 100%。

源码位置 ​

src/components/EstimatedProgressBar/index.vue

基本参数 ​

参数类型默认值说明
textstring-进度条上方的说明文案,通常用于提示当前任务状态。
durationSecondsnumber28模拟进度推进到 99% 的预计时长,单位为秒。
hideOnCompletebooleanfalse完成后是否自动隐藏进度条。

暴露方法 ​

参数类型默认值说明
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(),避免多次完成动画互相覆盖。

相关文档 ​