效果

实现方式
-  计时器:
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
 注意:下载安装字体后需要重启浏览器才生效



















