React - 红绿灯

今天在网上看到了一道 React 的红绿灯题目,就是试试将它写出来

用 React 实现一个信号灯(交通灯)控制器,要求:

默认情况下,红灯亮20秒,并且最后5秒闪烁绿灯亮20秒,并且最后5秒闪烁黄灯亮10秒,
次序为:红-绿-黄-红-绿-黄
灯的个数、颜色、持续时间、闪烁时间、灯光次序都可配置,
如:lights=[{color: ‘#fff’, duration: 10000, twinkleDuration: 5000}, … ]

Components
// light.js
import React, { Component } from 'react';
import './style.scss';


class Lights extends Component {
  static propTypes = {};

  static defaultProps = {};

  lightKey = 0;

  twinkTime = 300;

  constructor(props) {
    super(props);

    this.state = {
      lights: [
        { color: 'red', duration: 8000, twinkleDuration: 3000 },
        { color: 'yellow', duration: 3000 },
        { color: 'green', duration: 8000, twinkleDuration: 3000 }
      ]
    };
  }

  componentDidMount() {
    this.changeLight();
  }

  componentWillUnmount() {
    if (this.lightKey) {
      clearTimeout(this.lightKey);
    }
  }

  changeLight = (index = 0) => {
    const { lights } = this.state;
    const target = lights[index];
    if (target) {
      document.getElementsByClassName('lights')[0].style.setProperty('--bg-color', target.color);
      this.lightKey = setTimeout(() => {
        const key = (index + 1) === lights.length ? 0 : index + 1;
        this.changeLight(key);
      }, target.duration);

      if (target.twinkleDuration) {
        setTimeout(() => {
          this.handleTwinkleDuration(target.twinkleDuration, target.color);
        }, target.duration - target.twinkleDuration);
      }
    }
  }

  handleTwinkleDuration = (twinkleDuration, color) => {
    const time = twinkleDuration - this.twinkTime;
    let currentColor = document.getElementsByClassName('lights')[0].style.getPropertyValue('--bg-color');
    if (currentColor === 'gray') {
      currentColor = color;
    } else {
      currentColor = 'gray';
    }
    document.getElementsByClassName('lights')[0].style.setProperty('--bg-color', currentColor);
    if (time >= this.twinkTime) {
      setTimeout(() => {
        this.handleTwinkleDuration(time, color);
      }, this.twinkTime);
    }
  }


  render() {
    return (
      <div className="lights" />
    );
  }
}

export default Lights;

hook
import React, { useEffect } from 'react';
import './style.scss';

const Lights = ({ light: propsLights = '' }) => {
  let lightKey = 0;
  const twinkTime = 300;

  const defaultLights = [
    { color: 'red', duration: 8000, twinkleDuration: 3000 },
    { color: 'yellow', duration: 3000 },
    { color: 'green', duration: 8000, twinkleDuration: 3000 }
  ];
  const lights = propsLights || defaultLights;


  useEffect(() => {
    changeLight();
    // 清除定时器循环,不然会导致资源泄漏
    return () => clearInterval(lightKey);
  }, []);


  const changeLight = (index = 0) => {
    const target = lights[index];
    if (target) {
      document.getElementsByClassName('lights')[0].style.setProperty('--bg-color', target.color);
      lightKey = setTimeout(() => {
      	// 当默认设置走完,再从新开始循环
        const key = (index + 1) === lights.length ? 0 : index + 1;
        changeLight(key);
      }, target.duration);

      if (target.twinkleDuration) {
        setTimeout(() => {
          handleTwinkleDuration(target.twinkleDuration, target.color);
        }, target.duration - target.twinkleDuration);
      }
    }
  };

  const handleTwinkleDuration = (twinkleDuration, color) => {
    const time = twinkleDuration - twinkTime;
    let currentColor = document.getElementsByClassName('lights')[0].style.getPropertyValue('--bg-color');
    if (currentColor === 'gray') {
      currentColor = color;
    } else {
      currentColor = 'gray';
    }
    document.getElementsByClassName('lights')[0].style.setProperty('--bg-color', currentColor);
    if (time >= twinkTime) {
      setTimeout(() => {
        handleTwinkleDuration(time, color);
      }, twinkTime);
    }
  };

  return (
    <div className="lights" />
  );
};

export default Lights;

// style.scss

.lights {
  --bg-color: #eee;
  width: 50px;
  height: 50px;
  border: 1px solid #eee;
  border-radius: 27px;
  background-color: var(--bg-color);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值