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()

總結

沒有太多的詳細說明,我想看代碼以及註釋能看懂,若各位有看不懂或者覺得有問題的可以私聊我或者評論,大家一起共同進步

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章