非规则排列的进度条指的是进度段的长度、间距、样式不遵循统一规则,而是根据业务需求自定义每一段的属性,这种进度条在数据统计、任务流程展示等场景中非常实用,下面介绍基于Vue的实现方案。

实现思路梳理
非规则排列进度条的核心是将进度拆分为多个自定义段,每个段包含自身的长度占比、当前进度、样式配置等属性,通过Vue的响应式特性动态计算每一段的显示状态,最终组合成完整的进度条。
核心数据结构设计
首先需要定义进度段的基础数据格式,每个段需要包含以下关键属性:
- id:段的唯一标识
- total:该段的总长度占比(所有段的total之和应为100)
- current:该段当前的进度值
- color:该段的进度颜色
- bgColor:该段的背景颜色
响应式数据定义
在Vue组件的data中定义进度段数据和总进度值:
export default {
data() {
return {
// 非规则进度段配置,total总和为100
progressSegments: [
{
id: 1,
total: 30,
current: 20,
color: '#409eff',
bgColor: '#e4e7ed'
},
{
id: 2,
total: 20,
current: 15,
color: '#67c23a',
bgColor: '#e4e7ed'
},
{
id: 3,
total: 50,
current: 30,
color: '#e6a23c',
bgColor: '#e4e7ed'
}
],
// 进度条总宽度
barWidth: 600
}
}
}
进度条渲染逻辑
通过计算每个段的宽度占比,结合当前进度值,动态渲染每一段的进度显示效果。
计算属性处理
添加计算属性处理每一段的实际宽度和进度宽度:
export default {
// 上面的data配置省略
computed: {
// 处理每个进度段的显示数据
segmentList() {
return this.progressSegments.map(item => {
// 该段的实际宽度
const width = (item.total / 100) * this.barWidth
// 该段的进度宽度,不超过段总宽度
const progressWidth = Math.min((item.current / item.total) * width, width)
return {
...item,
width,
progressWidth
}
})
}
}
}
模板渲染代码
使用处理后的数据渲染进度条容器和每个进度段:
<template>
<div class="non-regular-progress">
<div class="progress-container" :style="{ width: barWidth + 'px' }">
<div
v-for="segment in segmentList"
:key="segment.id"
class="progress-segment"
:style="{ width: segment.width + 'px', backgroundColor: segment.bgColor }"
>
<div
class="segment-progress"
:style="{
width: segment.progressWidth + 'px',
backgroundColor: segment.color
}"
></div>
</div>
</div>
<div class="progress-info">
<div v-for="segment in segmentList" :key="segment.id" class="info-item">
<span class="info-color" :style="{ backgroundColor: segment.color }"></span>
<span>段{{ segment.id }}进度:{{ segment.current }}/{{ segment.total }}</span>
</div>
</div>
</div>
</template>
样式配置
添加对应的CSS样式让进度条显示正常:
.non-regular-progress {
padding: 20px;
}
.progress-container {
display: flex;
height: 20px;
border-radius: 10px;
overflow: hidden;
}
.progress-segment {
height: 100%;
position: relative;
margin-right: 2px;
}
.progress-segment:last-child {
margin-right: 0;
}
.segment-progress {
height: 100%;
border-radius: 10px;
transition: width 0.3s ease;
}
.progress-info {
margin-top: 15px;
display: flex;
gap: 20px;
}
.info-item {
display: flex;
align-items: center;
font-size: 14px;
color: #606266;
}
.info-color {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 2px;
margin-right: 5px;
}
动态更新进度
可以通过方法动态修改每个进度段的current值,由于Vue的响应式特性,进度条会自动更新:
export default {
// 上面的配置省略
methods: {
// 更新指定段的进度
updateSegmentProgress(id, newCurrent) {
const target = this.progressSegments.find(item => item.id === id)
if (target) {
// 限制进度不超过段的总长度
target.current = Math.min(newCurrent, target.total)
}
},
// 模拟进度更新
simulateProgress() {
this.progressSegments.forEach(item => {
const add = Math.floor(Math.random() * 5)
this.updateSegmentProgress(item.id, item.current + add)
})
}
}
}
注意事项
在实现过程中需要注意以下几点:
- 所有进度段的total属性之和需要保持为100,否则进度条总宽度会不符合预期
- 动态更新进度时,需要限制current值不超过对应段的total值,避免出现进度溢出
- 如果进度段之间的间距需要自定义,可以在progress-segment的样式中调整margin属性,或者新增spacing配置项
- 若需要支持点击进度条修改进度,可以给segment-progress添加点击事件,根据点击位置计算对应的进度值
非规则排列的进度条核心在于将整体进度拆分为可自定义的独立段,通过Vue的响应式机制动态计算每一段的显示状态,相比规则进度条灵活性更高,适配更多个性化场景。