coder-Tom

一个喜欢代码, 音乐,读书, 跑步, 记录生活的程序员

0%

用网页实现一个简易的时钟

很久没有更新文章了, 网上看到一个时钟的项目, 让我产生了非常强烈的兴趣, 下面是这种效果的实现方式, 朋友们也可以将它复制到自己的网站或者项目中

平时如果你没法专注的时候, 可以将这个效果做成一个网页, 个人感觉前面有一个时钟会让你意识到时间的流逝从而尽量的提高自己的工作效率

先看看下面的效果:

loading

其实这样的效果实现起来并不是太难, 我们需要做的就是先分析它的结构, 我们来看看代码:

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
<div class="clock" aria-label="00:00:00 AM">
<div class="clock__block clock__block--delay2" aria-hidden="true" data-time-group>
<div class="clock__digit-group">
<div class="clock__digits" data-time="a">00</div>
<div class="clock__digits" data-time="b">00</div>
</div>
</div>
<div class="clock__colon"></div>
<div class="clock__block clock__block--delay1" aria-hidden="true" data-time-group>
<div class="clock__digit-group">
<div class="clock__digits" data-time="a">00</div>
<div class="clock__digits" data-time="b">00</div>
</div>
</div>
<div class="clock__colon"></div>
<div class="clock__block" aria-hidden="true" data-time-group>
<div class="clock__digit-group">
<div class="clock__digits" data-time="a">00</div>
<div class="clock__digits" data-time="b">00</div>
</div>
</div>
<div class="clock__block clock__block--delay2 clock__block--small" aria-hidden="true" data-time-group>
<div class="clock__digit-group">
<div class="clock__digits" data-time="a">PM</div>
<div class="clock__digits" data-time="b">AM</div>
</div>
</div>
</div>

下面是css代码:

先用通配符选择器初始化网页,我们需要将box-sizing 的值设置为boder-box,就是边框盒

1
2
3
4
5
6
7
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}

来看看body的代码部分:

1
2
3
4
5
6
7
8
9
10
11
body {
background-color: var(--bg);
color: var(--fg);
font: 1em/1.5 "DM Sans", sans-serif;
height: 100vh;
display: grid;
place-items: center;
transition:
background-color var(--trans-dur),
color var(--trans-dur);
}

我们来看看全部的代码;

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--bg: hsl(var(--hue),90%,90%);
--fg: hsl(var(--hue),10%,10%);
--primary: hsl(var(--hue),90%,55%);
--trans-dur: 0.3s;
font-size: calc(16px + (20 - 16) * (100vw - 320px) / (1280 - 320));
}
body {
background-color: var(--bg);
color: var(--fg);
font: 1em/1.5 "DM Sans", sans-serif;
height: 100vh;
display: grid;
place-items: center;
transition:
background-color var(--trans-dur),
color var(--trans-dur);
}

.clock {
display: flex;
flex-direction: column;
flex-wrap: wrap;
align-items: center;
}
.clock__block {
background-color: hsl(var(--hue),10%,90%);
border-radius: 0.5rem;
box-shadow: 0 1rem 2rem hsla(var(--hue),90%,50%,0.3);
font-size: 3em;
line-height: 2;
margin: 0.75rem;
overflow: hidden;
text-align: center;
width: 6rem;
height: 6rem;
transition:
background-color var(--trans-dur),
box-shadow var(--trans-dur);
}
.clock__block--small {
border-radius: 0.25rem;
box-shadow: 0 0.5rem 2rem hsla(var(--hue),90%,50%,0.3);
font-size: 1em;
line-height: 3;
width: 3rem;
height: 3rem;
}
.clock__colon {
display: none;
font-size: 2em;
opacity: 0.5;
position: relative;
}
.clock__colon:before,
.clock__colon:after {
background-color: currentColor;
border-radius: 50%;
content: "";
display: block;
position: absolute;
top: -0.05em;
left: -0.05em;
width: 0.1em;
height: 0.1em;
transition: background-color var(--trans-dur);
}
.clock__colon:before {
transform: translateY(-200%);
}
.clock__colon:after {
transform: translateY(200%);
}
.clock__digit-group {
display: flex;
flex-direction: column-reverse;
}
.clock__digits {
width: 100%;
height: 100%;
}
.clock__block--bounce {
animation: bounce 0.75s;
}
.clock__block--bounce .clock__digit-group {
animation: roll 0.75s ease-in-out forwards;
transform: translateY(-50%);
}
.clock__block--delay1,
.clock__block--delay1 .clock__digit-group {
animation-delay: 0.1s;
}
.clock__block--delay2,
.clock__block--delay2 .clock__digit-group {
animation-delay: 0.2s;
}

/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: hsl(var(--hue),10%,10%);
--fg: hsl(var(--hue),10%,90%);
}
.clock__block {
background-color: hsl(var(--hue),90%,40%);
box-shadow: 0 1rem 2rem hsla(var(--hue),90%,60%,0.4);
}
.clock__block--small {
box-shadow: 0 0.5rem 2rem hsla(var(--hue),90%,60%,0.4);
}
}

/* Beyond mobile */
@media (min-width: 768px) {
.clock {
flex-direction: row;
}
.clock__colon {
display: inherit;
}
}

/* Animations */
@keyframes bounce {
from,
to {
animation-timing-function: ease-in;
transform: translateY(0);
}
50% {
animation-timing-function: ease-out;
transform: translateY(15%);
}
}
@keyframes roll {
from {
transform: translateY(-50%);
}
to {
transform: translateY(0);
}
}

这个时候的效果图:

image-20230223214114129

接下来就是JavaScript代码了, 这部分相对前面的部分, 我认为还是比较困难的

代码:

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
window.addEventListener("DOMContentLoaded",() => {
const clock = new BouncyBlockClock(".clock");
});
//在全局添加监听事件

class BouncyBlockClock {
constructor(qs) {
this.el = document.querySelector(qs);
this.time = { a: [], b: [] };
this.rollClass = "clock__block--bounce";
this.digitsTimeout = null;
this.rollTimeout = null;
this.mod = 0 * 60 * 1000;

this.loop();
}
animateDigits() {
const groups = this.el.querySelectorAll("[data-time-group]");

Array.from(groups).forEach((group,i) => {
const { a, b } = this.time;

if (a[i] !== b[i]) group.classList.add(this.rollClass);
});

clearTimeout(this.rollTimeout);
this.rollTimeout = setTimeout(this.removeAnimations.bind(this),900);
}
displayTime() {
// screen reader time
const timeDigits = [...this.time.b];
const ap = timeDigits.pop();

this.el.ariaLabel = `${timeDigits.join(":")} ${ap}`;

// displayed time
Object.keys(this.time).forEach(letter => {
const letterEls = this.el.querySelectorAll(`[data-time="${letter}"]`);

Array.from(letterEls).forEach((el,i) => {
el.textContent = this.time[letter][i];
});
});
}
loop() {
this.updateTime();
this.displayTime();
this.animateDigits();
this.tick();
}
removeAnimations() {
const groups = this.el.querySelectorAll("[data-time-group]");

Array.from(groups).forEach(group => {
group.classList.remove(this.rollClass);
});
}
tick() {
clearTimeout(this.digitsTimeout);
this.digitsTimeout = setTimeout(this.loop.bind(this),1e3);
}
updateTime() {
const rawDate = new Date();
const date = new Date(Math.ceil(rawDate.getTime() / 1e3) * 1e3 + this.mod);
let h = date.getHours();
const m = date.getMinutes();
const s = date.getSeconds();
const ap = h < 12 ? "AM" : "PM";

if (h === 0) h = 12;
if (h > 12) h -= 12;

this.time.a = [...this.time.b];
this.time.b = [
(h < 10 ? `0${h}` : `${h}`),
(m < 10 ? `0${m}` : `${m}`),
(s < 10 ? `0${s}` : `${s}`),
ap
];

if (!this.time.a.length) this.time.a = [...this.time.b];
}
}

这个就是上面的整个过程的代码, 感兴趣的同学可以研究一下

喜欢的朋友们可以给我点个赞哟