js实现交通灯(两种方案)
简介
刚在抖音上刷到一个面试题,说实现交通灯的方案,我一开始想到的是通过定时器去实现,没想到他提到了一个问询的方式去实现,借此记录下来,本文介绍了两种方案去实现交通灯以及对应的倒计时。废话不多说,上代码
html+css
html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Traffic Light</title>
</head>
<body>
<div class="traffic-light-container">
<div id="green" class="traffic-light"></div>
<div id="yellow" class="traffic-light"></div>
<div id="red" class="traffic-light"></div>
</div>
<div class="countdown">60</div>
<script src="./index.js"></script>
<!-- <script src="./index1.js"></script> -->
</body>
</html>
css如下:
.traffic-light {
width: 150px;
height: 150px;
margin: 10px;
border: 1px solid black;
display: inline-block;
border-radius: 50%;
}
.red { background-color: red; }
.yellow { background-color: yellow; }
.green { background-color: green; }
.countdown {
font-size: 24px;
margin-top: 20px;
}
定时器
index.js代码如下:
const redLight = document.getElementById('red');
const yellowLight = document.getElementById('yellow');
const greenLight = document.getElementById('green');
const countdownElement = document.querySelector('.countdown');
let currentTime = 5; // 初始倒计时时间
let currentLight = 'green'; // 初始交通灯颜色
greenLight.classList.add('green');
// 定义交通灯颜色变化的时间
const lightDurations = {
green: 5000, // 绿灯时间(毫秒)
yellow: 2000, // 黄灯时间(毫秒)
red: 7000 // 红灯时间(毫秒)
};
// 更新倒计时的函数
function updateCountdown() {
if (currentTime > 0) {
countdownElement.textContent = currentTime;
currentTime--;
setTimeout(updateCountdown, 1000);
} else {
changeLight();
}
}
// 切换交通灯颜色的函数
function changeLight() {
switch (currentLight) {
case 'green':
greenLight.classList.remove('green');
yellowLight.classList.add('yellow');
currentLight = 'yellow';
currentTime = lightDurations.yellow / 1000; // 转换为秒
break;
case 'yellow':
yellowLight.classList.remove('yellow');
redLight.classList.add('red');
currentLight = 'red';
currentTime = lightDurations.red / 1000; // 转换为秒
break;
case 'red':
redLight.classList.remove('red');
greenLight.classList.add('green');
currentLight = 'green';
currentTime = lightDurations.green / 1000; // 转换为秒
break;
}
updateCountdown(); // 重置倒计时
}
// 初始化倒计时
updateCountdown();
问询
index1.js代码如下:
class TrafficLight {
constructor(lights) {
this._lights = lights;
this._currentIndex = 0; // 记录当前灯下的索引
this._time = Date.now(); // 记录当前时间
}
_update() {
let disTime = this._disTime();
// 计算交通灯的展示时间总和
let total = this._lights.reduce((acc, cur) => {
return acc + cur.lasts
}, 0);
// 代表一个完整的循环周期的开始时间
this._time += total * Math.floor(disTime / total) * 1000
disTime = disTime % total; // 从上一个循环周期的开始到现在,还有多少时间没有用完
while (1) {
// 在每次循环中,disTime 被减去当前交通灯颜色的持续时间(this.currentLight.lasts)。
// 如果 disTime 仍然大于或等于 0,那么说明当前交通灯颜色还没有结束,
// 方法将 _time 向前推进当前交通灯颜色的持续时间,并更新 _currentIndex 为下一个交通灯颜色的索引
// 一旦 disTime 小于 0,说明当前交通灯颜色已经结束,循环终止。此时,_currentIndex 已经指向了下一个应该显示的交通灯颜色。
disTime -= this.currentLight.lasts;
if (disTime < 0) break
else {
this._time += this.currentLight.lasts * 1000
this._currentIndex = (this._currentIndex + 1) % this._lights.length;
// 将当前交通灯颜色的索引向前移动一个位置。如果当前已经是最后一个交通灯颜色,索引将回绕到数组的第一个元素。
// 这样,交通灯颜色就能按照数组中的顺序循环切换
}
}
}
// 访问器
get currentLight() {
return this._lights[this._currentIndex]
}
// 计算从上次更新到现在经过了多少秒
_disTime() {
return (Date.now() - this._time) / 1000
}
// 获取当前灯的状态
getCurrentLight() {
this._update()
return {
color: this.currentLight.color,
remain: this.currentLight.lasts - this._disTime()
}
}
}
const light = new TrafficLight([{
color: 'red',
lasts: 3
},
{
color: 'yellow',
lasts: 2
}, {
color: 'green',
lasts: 5
}
])
const countdown = document.querySelector('.countdown')
const trafficLightDom = document.querySelectorAll('.traffic-light')
function update() {
const current = light.getCurrentLight();
countdown.textContent = Math.ceil(current.remain)
trafficLightDom.forEach(item=>{
item.classList.remove('red', 'green', 'yellow')
if(item.id === current.color){
item.classList.add(current.color)
}
})
}
update()
// 动画,类似于定时器
function raf() {
requestAnimationFrame(() => {
raf()
update()
})
}
raf()
总结
没有太多的详细说明,我想看代码以及注释能看懂,若各位有看不懂或者觉得有问题的可以私聊我或者评论,大家一起共同进步