效果
实现方式
- 计时器:
setTimeout
或setInterval
来计时。setInterval
和setTimeout
在某些情况下可能会出现计时不准确的情况。这通常是由于JavaScript
的事件循环机制和其他代码执行所需的时间造成的。 - 问询:通过
getCurrentLight
将每个状态的持续时间设置为精确的值,并使用requestAnimationFrame
来递归调用getCurrentLight
函数,我们可以更准确地控制交通灯的状态。
源码
index.html
<!DOCTYPE html>
<html>
<head>
<title>交通灯</title>
<link type="text/css" rel="styleSheet" href="./index.css" />
</head>
<body>
<div class="traffic-light">
<div class="traffic-container">
<div class="light green"></div>
<div class="light yellow"></div>
<div class="light red"></div>
</div>
<div class="time">90</div>
</div>
<script type="module">
import {TrafficLight} from './TrafficLight.js';
const time = document.querySelector('.time');
const trafficDom = document.querySelector('.traffic-light');
const light = new TrafficLight(
{
red:3,
yellow:2,
green:5,
initial:'red',
}
);
function raf(){
requestAnimationFrame(()=>{
raf();
const current = light.getCurrentLight();
time.textContent =current.remain;
trafficDom.className = `traffic-light ${current.color}`;
console.log(current.color,current.remain);
})
}
raf();
</script>
</body>
</html>
index.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body{
width: 100vw;
height: 100vh;
margin: 0;
/* backgroud: #191c29 */
background: #fff;
}
.traffic-light{
width: 200px;
margin: 10px auto;
-webkit-box-flex: inherit;
text-align: center;
}
.light{
width: 20px;
height: 20px;
border-radius: 10px;
display:inline-block;
background-color: gray;
margin: 10px auto;
}
.red .red{
background-color: red;
}
.green .green{
background-color: green;
}
.yellow .yellow{
background-color: yellow;
}
.time{
font-family: 'DS-Digital';
font-size: 40px;
}
TrafficLight.js
export class TrafficLight {
constructor(options) {
const {
red = 60,
green = 60,
yellow = 3,
initial = 'green',
} = options || {};
this._colors ={
red:{
seconds: red,
next:'yellow',
},
green:{
seconds: green,
next:'yellow',
},
yellow:{
seconds : yellow,
},
};
this._switch(initial);
}
_switch(color){
this._currentColor = color;
this._seconds = this._colors[color].seconds;
this._time = Date.now();
}
_next(){
if(this._currentColor === 'red'){
this._colors.yellow.next = 'green';
}
else if(this._currentColor === 'green'){
this._colors.yellow.next = 'red';
}
else{
}
this._switch(this._colors[this._currentColor].next);
}
getCurrentLight(){
const remain = Math.ceil(this._seconds -(Date.now() - this._time)/1000);
if(remain<=0){
this._next();
return this.getCurrentLight();
}
return {
color: this._currentColor,
remain,
};
}
}
字体 DS-Digital
下载字体 DS-Digital
注意:下载安装字体后需要重启浏览器才生效