Progress Steps

项目来自github上的50projects50days,用于巩固自己的CSS及JS基础,倒也挺有趣

需求

Progress steps需要制作一个步骤条,由两个按钮控制步骤前进后退,并且在边界条件按钮禁用

image-20220614230706095

分析

应该算是一个非常常见的需求,其中最重要的就是中间步骤条的显示

我们可以很轻松的想到在JS中用一个数来纪录走过的步骤,但每个步骤之后的横线是一个问题

一开始想着对每个子项添加一个伪元素来显示横线,再添加定位处理,但是这样最后一个子项会多出一条横线较为麻烦

但是给子项的容器直接添加伪元素再通过定位移至中央就可以直接显示出来。

那么如何标记走过的路程呢?

需要在所有子项之前新加一项用来展示路迹,它的width可以先设置为0%

当我们点击按钮的时候,会对数据进行处理,如果超过长度则重置为最长,减小同理。在步骤增加的过程中通过forEach函数将节点下标与长度进行比较,小于长度的节点设置active样式,然后根据已有active样式的节点数量算出占据的长度来显示“痕迹”。

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!--
* @Author: CQJ
* @Date: 2022-06-14 16:43:01
* @LastEditors: CQJ
* @LastEditTime: 2022-06-14 23:18:10
* @Description: 步骤条
-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<div class="wrap">
<div class="main">
<ul class="list">
<div id="line"></div>
<li class="active">1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
<div class="btn">
<button id="prev" disabled>Prev</button>
<button id="next">Next</button>
</div>
</div>
</div>
</body>

<script src="./script.js"></script>
</html>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}

:root{
--line-border-fill:#3498db;
--line-border-empty:#e0e0e0;
}

.wrap {
width: 100vw;
height: 100vh;
background-color: rgb(246, 247, 251);
font-family: 'Muli',sans-serif;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
}


.list {
display: flex;
width: 350px;
justify-content: space-between;
position: relative;
max-width: 100%;
}

.list::before{ /*为元素制造横条*/
content: '';
background-color: var(--line-border-empty);
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
height: 4px;
width: 100%;
z-index: 0;
}

#line{ /*显示已走长度*/
background-color: var(--line-border-fill);
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
height: 4px;
width: 0%;
z-index: 0;
transition: .4s ease;
}

ul li {
list-style: none;
width: 30px;
height: 30px;
border-radius: 50%;
background-color: #fff;
color: rgb(153, 166, 196);
display: flex;
justify-content: center;
align-items: center;
border: 3px solid var(--line-border-empty);
position: relative;
}



.active {
border: 3px solid var(--line-border-fill);
}

.btn {
margin-top: 30px;
display: flex;
justify-content: center;
}

button {
background-color: var(--line-border-fill);
color: #fff;
border: none;
font-size: 14px;
font-family: inherit;
border-radius: 6px;
padding: 8px 30px;
margin: 5px;
cursor: pointer;
}

button:active{
transform: scale(.98);
}

button:focus{
outline:0;
}

button:disabled { /*设置禁用样式*/
background-color: var(--line-border-empty);
cursor: not-allowed;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/*
* @Author: CQJ
* @Date: 2022-06-14 16:43:15
* @LastEditors: CQJ
* @LastEditTime: 2022-06-14 22:44:00
* @Description: JS
*/
let len = 1 //默认激活的只有一个按钮
let nextbtn = document.querySelector('#next')
let prebtn = document.querySelector('#prev')
let cirarr = document.querySelectorAll('li')
let progress = document.getElementById('line')

nextbtn.addEventListener('click', () => {
len++
if (len > cirarr.length) {
len = cirarr.length
}
update()
})

prebtn.addEventListener('click', () => {
len--
if (len < 1) {
len = 1
}
update()
})

function update() {
cirarr.forEach((circle, index) => {
if (index < len) { //给走过的标记
circle.classList.add('active')
} else {
circle.classList.remove('active')
}
})
const actives = document.querySelectorAll('.active')
progress.style.width = ((actives.length - 1) / (cirarr.length - 1)) * 100 + '%' //动态获取长度

if (len === 1) {
prebtn.disabled = true
} else if (len === cirarr.length) {
nextbtn.disabled = true
} else {
prebtn.disabled = false
nextbtn.disabled = false
}
}

总结

最重要的两个点在于:伪元素设置横条

foreach设置样式后动态设置长度


Progress Steps
https://blog-theta-ten.vercel.app/2022/06/14/Progress-Steps/
作者
Chen
发布于
2022年6月14日
许可协议