簡介
剛在抖音上刷到一個面試題,說實現交通燈的方案,我一開始想到的是通過定時器去實現,沒想到他提到了一個問詢的方式去實現,藉此記錄下來,本文介紹了兩種方案去實現交通燈以及對應的倒計時。廢話不多說,上代碼
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()
總結
沒有太多的詳細說明,我想看代碼以及註釋能看懂,若各位有看不懂或者覺得有問題的可以私聊我或者評論,大家一起共同進步