要求: 用Vue实现一个信号灯(交通灯)控制器,要求:
- 默认情况下,红灯亮20秒并且最后闪烁,绿灯亮20秒并且最后5秒闪烁,黄灯亮10秒,之后回到红灯,以此不断重复循环,次序为:红-绿-黄-红-绿-黄
- 支持扩展:灯光的个数、颜色、持续事件、闪烁事件、灯光次序都是可配置的,例如:const lights = [{color: “red”, duration: “20000”, twinkleDuration: 5000},{color: “green”, duration: “20000”, twinkleDuration: 5000},{color: “yellow”, duration: “10000”, twinkleDuration: 0}];
- 尽可能用到你所指导的ESNext特性
<!-- TrafficLight.vue 交通信号灯 -->
<template>
<div class="traffic-lights">
<light
ref="lightsRef"
v-for="(item, index) in lights"
:key="index"
:setting="{color: item.color, duration: item.duration, twinkleDuration: item.twinkleDuration}"
>
</light>
<button @click="stopFn()">暂停</button>
<button @click="continueFn()">继续</button>
<tree/>
</div>
</template>
<script>
import light from "./light";
export default {
name: "TrafficLight",
components: { light },
data() {
return {
activeIdx: 0,
lights: [
{
color: "red",
duration: 20000,
twinkleDuration: 5000,
},
{
color: "green",
duration: 20000,
twinkleDuration: 5000,
},
{
color: "yellow",
duration: 10000,
twinkleDuration: 0,
},
],
};
},
mounted() {
this.initLightsDataFn(this.lights);
},
methods: {
/**
* @description 初始化所有的灯的状态
* @param {Array} lightsInfoArr 所有灯的状态信息
*/
initLightsDataFn(lightsInfoArr) {
this.lights = lightsInfoArr;
this.initCurrentLightStatus(0); // 初始化第一盏灯
},
/**
* @description 激活当前灯的状态
* @param {Number} idx 灯的状态数组中激活灯的下标
*/
initCurrentLightStatus(idx) {
const maxLength = this.lights.length || 3;
this.activeIdx = idx % maxLength;
if (this.$refs["lightsRef"] && this.$refs["lightsRef"][this.activeIdx]) {
let result = this.$refs["lightsRef"][this.activeIdx].keepLightActiveFn(); // 激活当前灯的状态
result.then(() => {
this.initCurrentLightStatus(this.activeIdx + 1); // 递归执行下一盏灯
});
}
},
// 按钮-暂停
stopFn() {
if (this.$refs["lightsRef"] && this.$refs["lightsRef"][this.activeIdx]) {
this.$refs["lightsRef"][this.activeIdx].stopFn();
}
},
// 按钮-继续
continueFn() {
this.initCurrentLightStatus(this.activeIdx);
},
},
};
</script>
<style scoped>
.traffic-lights {
display: flex;
}
</style>
<!-- lights.vue 信号灯组件 -->
<template>
<div
class="light-box"
:style="{ backgroundColor: activeStatus && !twinkleDurationStatus ? setting.color : ''}"
></div>
</template>
<script>
export default {
props: {
setting: {
type: Object,
default: {
color: "red",
duration: 20000, // 持续总时长
twinkleDuration: 5000, // 闪烁时长
},
},
},
data() {
return {
activeStatus: false, // 是否激活状态
twinkleDurationStatus: false, //闪烁状态
workingTime: 0, //当前持续时长
timer: "", // 定时器
};
},
mounted() {},
methods: {
keepLightActiveFn(interval = 100) {
return new Promise((resolve) => {
if (!this.timer)
this.timer = setInterval(() => {
const { duration, twinkleDuration } = this.setting;
this.workingTime += interval;
if (this.workingTime < duration && !this.activeStatus) { //整个持续时间内保证激活灯的状态
this.activeStatus = true;
}
if ( this.workingTime >= duration - twinkleDuration && this.workingTime < duration) { // 闪烁时间
this.twinkleDurationStatus = !this.twinkleDurationStatus; // 改变灯的状态
} else if (this.workingTime >= duration) { //超过持续总时长
this.stopFn();
this.workingTime = 0;
resolve(true);
}
}, interval);
});
},
stopFn() {
this.activeStatus = false; // 关灯
clearInterval(this.timer);
this.timer = ''
},
},
};
</script>
<style scoped>
.light-box {
width: 50px;
height: 50px;
border-radius: 50%;
margin: 20px;
border: 1px solid #333;
}
</style>
以上仅个人代码分享