第一步
<template>
<!-- 进度条组件 -->
<div class="progress-bar">
<!-- 背景 -->
<div class="bg"></div>
<!-- 进度条 -->
<div class="bar" :style="{ width: progress + '%' }"></div>
<!-- 进度显示文本 -->
<div class="label">{{ progress }}%</div>
</div>
</template>
第二步
子组件中
<script lang="ts" setup>
import { ref, reactive, onMounted, defineProps } from 'vue'
import { useRoute, useRouter } from 'vue-router'
const props = defineProps({
progress: {
type: Number,
required: true
}
})
const route = useRoute()
const router = useRouter()
const progress = ref<any>(0)
progress.value = props.progress
const isPlaying = ref<any>(false)
const isCompleted = ref<any>(false)
onMounted(() => {
start()
})
// 开始进度动画
const start = () => {
isPlaying.value = true;
// 开始从0%到90%的动画,并在完成后继续到100%
animateProgress(100).then(() => {
if (!isCompleted.value) {
animateProgress(100);
}
}).catch((error) => {
console.log('Progress error', error);
finish()
});
}
const animateProgress = (target: number) => {
// 返回一个Promise对象,用于异步操作
return new Promise((resolve: any, reject: any) => {
// 初始化起始值、目标值和动画持续时间
let start = progress.value;
const end = target;
const duration = (target - start) * 150;
// 执行动画的函数
const doAnimation = () => {
// 计算动画流逝的时间
const elapsed = Date.now() - startTime;
// 计算当前进度百分比
const Progress = Math.min(elapsed / duration, 1);
// 更新进度值
progress.value = start + ((end - start) * Progress);
// 可选:保留小数点后两位或不保留toFixed(填入0-2);
// 例如:保留俩位就(start + ((end - start) * Progress)).toFixed(2);
// 例如:不保留位就(start + ((end - start) * Progress)).toFixed(0);
// 判断动画是否完成
if (Progress === 1) {
resolve();
} else if (isCompleted.value) {
resolve();
} else {
// 继续执行下一帧动画
requestAnimationFrame(doAnimation);
}
};
// 记录动画开始时间
const startTime = Date.now();
// 启动第一帧动画
requestAnimationFrame(doAnimation);
});
}
const finish = () => {
isCompleted.value = true;
progress.value = 100;
}
</script>
父组件
<template>
<div>
<Porgress :progress="0" />
</div>
</template>
<script lang="ts" setup>
import Porgress from '@/components/Progress.vue';
</script>
子组件样式
<style lang="scss" scoped>
.progress-bar {
position: relative;
width: 50%;
height: 8px;
margin: 500px auto;
}
.bg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #ccc;
border-radius: 5px;
}
.bar {
position: absolute;
top: 0;
left: 0;
height: 100%;
border-radius: 5px;
background-color: #409eff;
transition: width 0.5s;
}
.label {
position: absolute;
top: -20px;
left: calc(100% + 5px);
color: #333;
font-size: 12px;
}
</style>