用 React 实现一个信号灯(交通灯)控制器,要求:
- 默认情况下,红灯亮20秒,并且最后5秒闪烁绿灯亮20秒,并且最后5秒闪烁黄灯亮10秒, 次序为:红-绿-黄-红-绿-黄
- 灯的个数、颜色、持续时间、闪烁时间、灯光次序都可配置,如:lights=[{color: '#fff', duration: 10000, twinkleDuration: 5000}, ... ]
思路
考虑用hooks实现,单个灯可以提取成单个组件,用父组件控制灯的亮灭,可设定当前序号(分别为0, 1, 2),当轮到某个序号时这个灯亮。子组件内部用setTimeout控制亮,用setInterval控制闪动,用改变class控制灯的颜色。关键代码如下:
灯组件:Light.js
import React, { useState, useEffect } from "react";
export const Light = (props) => {
const defaultColor = props.color;
const OFF_COLOR = "black";
const [color, setColor] = useState(props.color);
useEffect(() => {
let timerId;
if (props.on) {
setColor(defaultColor);
const twMax = props.twinkleDuration / props.twinkleInterval;
let tw_count = 0;
timerId = setTimeout(() => {
if (props.twinkle) {
timerId = setInterval(() => {
if (tw_count >= twMax) {
props.callback();
clearInterval(timerId);
setColor(OFF_COLOR);
return;
}
if (tw_count % 2) {
setColor(defaultColor);
} else {
setColor(OFF_COLOR);
}
tw_count++;
}, props.twinkleInterval);
} else {
props.callback();
}
}, props.duration);
} else {
if (timerId) {
clearTimeout(timerId);
}
setColor(OFF_COLOR);
}
//eslint-disable-next-line
}, [props.on]);
return <div className={`light color-${color}`}></div>;
};
App.js
import React, { useState } from "react";
import { Light } from "./Light";
import "./App.css";
export default function App() {
const lights = [
{
color: "red", // 颜色
on: false, // 开关
twinkle: true, // 最后是否闪烁
twinkleDuration: 6000, // 闪烁时间
twinkleInterval: 1000, // 闪烁间隔
duration: 20000 // 恒亮时间
},
{
color: "green",
on: false,
twinkle: true,
twinkleDuration: 6000,
twinkleInterval: 1000,
duration: 20000
},
{
color: "yellow",
on: false,
twinkle: false,
duration: 10000
}
];
let [cur, setCur] = useState(0);
const callback = () => {
setCur((cur+1) % 3);
}
return (
<div className="App">
{lights.map((item, index) => (
<Light
key={index}
on={cur === index}
color={item.color}
twinkleDuration={item.twinkleDuration}
twinkleInterval={item.twinkleInterval}
duration={item.duration}
twinkle={item.twinkle}
callback={callback} // 向子组件传入callback以控制当前序号
/>
))}
</div>
);
}
CSS
.App {
font-family: sans-serif;
text-align: center;
margin: 0 auto;
}
.light {
width: 100px;
height: 100px;
border-radius: 50%;
margin: 5px 0;
}
.color-red {
background: red;
}
.color-green {
background: green;
}
.color-yellow {
background: yellow;
}
.color-black {
background: black;
}
最后效果:8lybq.csb.app/
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!