这是MProjectsNDays的第2个项目,可点击体验,名字我不知道怎么翻译为中文更好,但是大家看到效果后一定能意会:
其中第二个纵向的效果是我在原版的基础上拓展而来的,以此为基础可以实现常见的物流跟踪效果。
老规矩,首先看html布局:
<body>
<div class="container">
<div class="progress-container">
<div class="progress" id="progress"></div>
<div class="circle active">1</div>
<div class="circle">2</div>
<div class="circle">3</div>
<div class="circle">4</div>
</div>
<button class="btn" id="prev" disabled>上一步</button>
<button class="btn" id="next">下一步</button>
</div>
<script src="script.js"></script>
</body>
html非常简单,不再赘述,等下结合css做讲解。
核心css如下:
:root {
--line-border-fill: #3498db;
--line-border-empty: #e0e0e0;
}
:root表示整个html的根元素,其他元素都是后代。那么在此处的用处就是定义了两个全局变量,方便后续使用。使用的方法有两种,第二种可以指定默认值。
var(--line-border-empty)
var(--line-border-empty,#000)
.progress-container {
display: flex;
justify-content: space-between;
position: relative;
margin-bottom: 30px;
width: 350px;
}
progress-container使用了flex布局,space-between表示均匀排列每个元素,首个元素放置于起点,末尾元素放置于终点
.progress-container::before {
content: '';
background-color: var(--line-border-empty);
position: absolute;
height: 4px;
top: 50%;
width: 100%;
transform:translateY(-50%);
z-index: -1;
}
将background-color: var(--line-border-empty);去掉,进度条底色就不见了,如下图所示:
可见,上述css核心功能就是生成进度条底色。
content: ''——与 :before及 :after伪元素配合使用,插入生成内容。此处没有内容,如果去掉的话会有问题,如图:
position: absolute——与progress-container中的position: relative前后呼应,表示相对于progress-container进行定位。
这里补充下这两个属性的知识:
relative:生成相对定位的元素,相对于其正常位置进行定位
absolute:生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位
top: 50%——向上间隔50%的高度。由于自身的高度,单纯使用此属性并不会居中。 transform:translateY(-50%)——向上移动自身高度的50%,与上个属性结合便可以实现垂直居中。 为了便于直观理解,我这里放两张图,分别去掉其中一个属性:
第二个图需要仔细一点才能看出进度条底色没有垂直居中,因为其自身高度很小,所以没有偏移一半也不明显。
z-index: -1——设置元素的堆叠顺序。拥有更高堆叠顺序的元素处于较低元素的前面。 这里去掉该属性来感受一下:
.progress {
background-color: var(--line-border-fill);
position: absolute;
height: 4px;
top: 50%;
width: 0%;
transform:translateY(-50%);
z-index: -1;
transition: 0.4s ease;
}
这是进度条样式,有了progress-container::before的讲解,这里便无需赘述了,只在最后加入了动画:transition: 0.4s ease。
.circle {
background-color: #fff;
color: #999;
border-radius: 50%;
height: 30px;
width: 30px;
display: flex;
align-items: center;
justify-content: center;
border: 3px solid var(--line-border-empty);
transition: 0.4s ease;
}
.circle.active {
border-color: var(--line-border-fill);
}
circle定义了圆的样式,使用flex布局的三条属性是为了使圆中的数字居中,不是核心。.circle.active则定义了进度为当前位置时圆的样式,即将边框颜色改变了。
.btn {
background-color: var(--line-border-fill);
color: #fff;
border: 0;
border-radius: 6px;
margin: 5px;
padding: 8px 30px;
}
.btn:active {
transform: scale(1.05);
}
.btn:disabled {
background-color: var(--line-border-empty);
cursor: not-allowed;
}
以上是按钮相关的样式,transform: scale(1.05)使得按钮被点击时放大。
js代码如下,其实也非常简单,只是对按钮、圆圈和进度条做了一些控制。
const progress = document.getElementById('progress')
const prev = document.getElementById('prev')
const next = document.getElementById('next')
const circles = document.querySelectorAll('.circle')
const verticel = document.querySelector('.vertical')
let currentActive = 1
next.addEventListener('click', () => {
currentActive++;
if (currentActive > circles.length) {
currentActive = circles.length;
}
update();
})
prev.addEventListener('click', () => {
currentActive--;
if (currentActive < 1) {
currentActive = 1;
}
update();
})
function update() {
// circle状态控制
circles.forEach((circle, index) => {
if (currentActive < index + 1) {
circle.classList.remove('active');
} else {
circle.classList.add('active');
}
})
// 按钮状态控制
if(currentActive <= 1) {
prev.disabled = true;
}else if(currentActive >= circles.length) {
next.disabled = true;
}else {
next.disabled = false;
prev.disabled = false;
}
// 设置进度条长度
if(verticel) {
progress.style.height = (currentActive - 1) * 100 / (circles.length - 1) + '%';
}else {
progress.style.width = (currentActive - 1) * 100 / (circles.length - 1) + '%';
}
}
注意最后设置了进度条长度部分进行了判断,如果是垂直方向的进度条,改变的就是高度;如果是水平方向的,改变的则是宽度。 除了js代码之外,要实现垂直模式的效果,css部分也有所增加:
.progress-container.vertical {
flex-direction: column;
align-items: center;
height: 350px;
}
.vertical::before {
width: 4px;
right: 50%;
height: 100%;
top: 0%;
transform:translateX(50%);
}
.progress.vertical {
top: 0%;
width: 4px;
right: 50%;
height: 0%;
transform:translateX(50%);
}
其思路与水平方向是相对的,此处不再赘述。
至此,整个项目就完成了! 完整源码可在此查看