由于el-steps不支持小数,没法实现激活状态走到一半的效果,通过el-progress做样式重合来实现,要做得需求效果如下:
- 我是将示例写在弹窗中进行测试的
<el-dialog
v-model="dialogVisible"
title="Tips"
width="1000"
:close-on-click-modal="false"
@opened="getStepsWidth"
>
<div class="steps-container">
<el-steps :active="1" finish-status="success" ref="stepsRef">
<el-step title="Step 1"></el-step>
<el-step title="Step 2"></el-step>
<el-step title="Step 3"></el-step>
<el-step title="Step 4"></el-step>
<el-step title="Step 5"></el-step>
</el-steps>
<div class="progress-overlay">
<div class="custom-progress">
<div class="progress-label">1.5</div>
</div>
</div>
</div>
</el-dialog>
补充:如果想要实现动态走到某一节点后的一半,这样实现:
1. progressWidth动态绑定值
<div class="steps-container">
<el-steps :active="active" ref="stepsRef">
<template v-for="(items, index) in statusInfor.statusBar">
<el-step :title="items.period" :description="items.name" />
</template>
</el-steps>
<div class="progress-overlay" v-if="statusInfor.statusDue">
<div
class="custom-progress"
:style="{ width: progressWidth }"
>
<div
class="progress-label"
:style="{ left: progressWidth }"
>
{{ statusInfor.submitDatePeriod }}
</div>
</div>
</div>
</div>
2. 同时,由于无法直接通过 Vue 的 style 绑定来控制伪元素的属性, custom-progress::before 的 width 通过 width: inherit 从父元素继承宽度,父元素的宽度通过动态 style 绑定控制。则动态绑定时直接给 class="custom-progress"来添加width宽度,::before直接继承父级宽度。
// ------steps--------------------
.steps-container {
position: relative;
}
.el-steps__line {
position: relative;
z-index: 1;
}
.el-steps__line-inner {
background-color: #e5e5e5;
}
.custom-progress::before {
content: "";
position: absolute;
top: -32px;
left: 0;
// width: calc(224px * (2 - 1) + 224px / 2); /* 表示从步骤 1 到 1.5 */
// custom-progress::before 的 width 通过 width: inherit 从父元素继承宽度,父元素的宽度通过动态 style 绑定控制。
// 因为无法直接通过 Vue 的 style 绑定来控制伪元素的属性
width: inherit; // 重要*******重要************重要********重要************重要********
height: 2px;
background-color: #409eff;
// z-index: 2; /* 确保蓝色进度条显示在步骤条上方 */
}
.progress-overlay {
position: relative;
top: -20px; /* 调整此处,控制进度条相对步骤条的偏移 */
}
.progress-label {
position: absolute;
/* 调整文本距离进度条的间距 */
top: -9px;
/* 定位到1.5的准确位置 */
// left: calc(25% / 2);
// left: calc(224px * (2 - 1) + 224px / 2); /* 表示从步骤 1 到 1.5 */
transform: translateX(-50%);
color: #409eff;
font-size: 12px; /* 控制字体大小 */
}
.el-step.is-process + .el-step::before {
background-color: transparent; /* 防止步骤条默认的灰色覆盖蓝色进度条 */
}
.el-step__head.is-process::after {
background-color: #409eff; /* 确保图标处的背景色与进度条一致 */
}
::v-deep .el-step__icon {
z-index: 10 !important;
}
- 弹窗打开时获取el-steps的总长度,因为在mounted中获取不到,弹窗没打开。@opened="getStepsWidth" 属性。
const getStepsWidth = () => {
// Ensure the steps component is rendered before trying to access its width
if (stepsRef.value) {
const stepsWidth = stepsRef.value.$el.offsetWidth;
console.log("Steps total width:", stepsWidth / 4);
}
};
- 添加样式
.steps-container {
position: relative;
}
.el-steps__line {
position: relative;
z-index: 1;
}
.el-steps__line-inner {
background-color: #e5e5e5;
}
.custom-progress::before {
content: "";
position: absolute;
top: -26px;
left: 0;
width: calc(233px * 3 / 2); /* 表示从步骤 1 到 1.5 */
height: 2px;
background-color: blue;
z-index: 2; /* 确保蓝色进度条显示在步骤条上方 */
}
.progress-overlay {
position: relative;
top: -20px; /* 调整此处,控制进度条相对步骤条的偏移 */
}
.progress-label {
position: absolute;
/* 调整文本距离进度条的间距 */
top: -20px;
/* 定位到1.5的准确位置 */
// left: calc(25% / 2);
left: calc(233px * 3 / 2); /* 表示从步骤 1 到 1.5 */
transform: translateX(-50%);
color: blue;
font-size: 12px; /* 控制字体大小 */
}
.el-step.is-process + .el-step::before {
background-color: transparent; /* 防止步骤条默认的灰色覆盖蓝色进度条 */
}
.el-step__head.is-process::after {
background-color: blue; /* 确保图标处的背景色与进度条一致 */
}
::v-deep .el-step__icon {
z-index: 10;
}
优化后的:
<div class="steps-container">
<el-steps :active="active" ref="stepsRef">
<template v-for="(items, index) in statusInfor.statusBar">
<el-step :description="items.name">
<template #title>
<span
:style="{
color: items.markColor === 1 ? 'red' : 'inherit',
}"
>
{{ items.period }}
</span>
</template>
</el-step>
</template>
</el-steps>
<div class="progress-overlay" v-if="statusInfor.statusDue">
<div
class="custom-progress"
:style="{ width: progressWidth }"
>
<div
class="progress-label"
:style="{ left: progressWidth }"
:title="`submitted for ${statusInfor.submitDatePeriod}`"
>
{{ statusInfor.submitDatePeriod }}
</div>
</div>
</div>
</div>
方法:
// 添加类似进度条效果
if (stepsRef.value) {
const stepsWidth: any = stepsRef.value.$el.offsetWidth;
// console.log("Steps total width:", stepsWidth, stepsWidth / 7);
let greyCount = statusInfor.value.greyIndex + 1;
let activeCount = 0;
for (
let index = statusInfor.value.statusBar.length - 1;
index >= 0;
index--
) {
let statusBarItem = statusInfor.value.statusBar[index];
if (statusBarItem.active) {
activeCount = index + 1;
break;
}
}
let singlePx: any =
parseInt(stepsWidth) / (statusInfor.value.statusBar.length - 1);
progressWidth.value = `calc(${singlePx}px * (${activeCount} - 1) + ${singlePx}px / 2)`;
// progressWidth.value = "calc(224px * (6 - 1) + 224px / 2)";
// --------给跳转的节点添加灰色(节点样式)-----------------------------------------
const stepIcons = document.querySelectorAll(".el-step__icon-inner");
// 找到需要添加灰色边框的元素
const stepIconWithFive = Array.from(stepIcons).find(
(icon) => icon.textContent.trim() === "" + (greyCount - 1)
);
// 如果找到了该元素,则设置其父元素的父元素的边框
if (stepIconWithFive) {
const parentElement = stepIconWithFive.closest(".el-step__icon");
parentElement.style.border = "2px solid gray";
parentElement.style.color = "gray";
}
// --------给跳转的节点添加灰色(描述文本)-----------------------------------------
const stepDescriptions = document.querySelectorAll(".el-step__description");
const index = greyCount - 2; // 描述的索引与 greyCount 相同
if (stepDescriptions[index]) {
stepDescriptions[index].style.color = "gray"; // 设置描述文本为灰色
}
}