昨天刷視頻,都是關于新國標紅綠燈的,看大家議論紛紛,下班就用150行代碼通過Vue組件實踐紅綠模擬演示,視頻也跟大家展示過了,今天接著更新圖文版本,大家跟著優雅哥通過該案例實操模擬一下,
不過新國標紅綠燈的設計,這個專業性、邏輯性、藝術性就是厲害,三個方向 * 三種顏色,玩轉九宮格,大部分場景都可以不加思考就知道應該通行或者等待,只有某些情況下對應行駛方向的燈不亮時,才需要 if ... else ... 判斷,優雅哥比較腦殘,無論哪個方向:左轉、直行、右轉,如果燈都亮著,不就可以一眼看出能否通行了嗎,對應方向紅燈就停、綠燈就通行,這樣是不是就可以不需要思考了?或許專家是為了省電吧,三個方向都亮燈太費電了,
后面得知,關于新國標紅綠燈資訊是誤傳,以上說辭純屬個人當時根據資訊的一些看法,請大家不要誤以為真,
現在來說說作為程式員,咱就用 Vue3 來模擬新國標紅綠燈玩一玩,
1 組件分析
組件化開發是我們一貫的風格,如何進行這個紅綠燈組件的設計呢?

從上圖可以看出我對新國標紅綠燈的組件拆分,
1.1 lamp
lamp 代表每個燈,在上圖中一共有9個燈,分別是左轉三個顏色的燈、直行三個顏色的燈、右轉三個顏色的燈,這 9 個燈的區別是顏色和內部的箭頭,而內部的箭頭與車輛行駛方向(左轉、右轉、直行)有關,故顏色和方向可定義為屬性,由外部傳遞,
1.2 lamp-group
圖中一共有三個 lamp-group,每個行駛方向的三個顏色的燈組成一個 lamp-group,同樣的,lamp-group 有一個屬性為方向,該屬性表示左轉、直行或右轉,此外,每個 lamp-group 中最多只有一個燈亮,故可以定義一個屬性為狀態,表示這個 lamp-group 中哪個燈亮、或者都不亮,
1.3 traffic-lamp
traffic-lamp 表示整個新國標紅綠燈,有三個 lamp-group 組成,整個紅綠燈也需要一個狀態屬性,描述三個方向的 lamp-group 的狀態,
2 全域檔案定義
2.1 樣式變數
在 src/assets/ 中創建目錄 scss,并在該目錄下創建樣式變數檔案 traffic-lamp-common.scss,在該檔案中定義紅黃綠顏色、間距等常見樣式,便于全域保持一致,由于咱 demo 較小,將 scss 變數與通用樣式定義在一起就可以了,如果在正式開發中,要遵守 CSS 架構規范,無論是 ITCSS 還是 SMACSS,
src/assets/scss/traffic-lamp-common.scss:
$red: #e42621;
$yellow: #eecd48;
$green: #59e02e;
$commonPadding: 10px;
$commonMargin: 10px;
$lampSize: 80px;
$radius: 8px;
.red {
color: $red !important;
}
.yellow {
color: $yellow !important;
}
.green {
color: $green !important;
}
.bg-red {
background-color: $red !important;
}
.bg-yellow {
background-color: $yellow !important;
}
.bg-green {
background-color: $green !important;
}
2.2 常量定義
創建 src/common/traffic-lamp-common.ts,在該檔案中定義兩個列舉類,分別是行駛方向(左、直、右)和燈的狀態,O - off 表示燈不亮,
export enum Direction {
L = 'left',
C = 'center',
R = 'right'
}
export enum Status {
R = 'red',
Y = 'yellow',
G = 'green',
O = 'off'
}
2.3 匯入資源
由于燈里面有左箭頭、右箭頭兩個圖示,故從 iconfont 上搜索并下載這兩個圖示,優雅哥采用 iconfont 的方式使用圖示,資源檔案位于 src/assets/iconfont 下,在 main.ts 中引入iconfont:
import '@/assets/iconfont/iconfont.css'
3 組件開發
在 src/components 目錄下創建目錄 traffic-lamp,上面分析的三個組件就在該目錄下開發,
3.1 實作 lamp 組件
lamp.vue:
<template>
<div :>
<span v-if="direction === Direction.L" ></span>
<span v-if="direction === Direction.R" ></span>
</div>
</template>
<script lang="ts" setup>
import { computed, defineProps, PropType } from 'vue'
import { Direction, Status } from '@/common/traffic-lamp-common'
const props = defineProps({
direction: {
type: String as PropType<Direction>,
required: true
},
color: {
type: String as PropType<Status>,
required: false,
default: Status.O
}
})
const colorClass = computed(() => {
if (!props.color) {
return ''
}
return `${props.direction}` === Direction.C ? `bg-${props.color}` : props.color
})
</script>
<style scoped lang="scss">
@import "~@/assets/scss/traffic-lamp-common.scss";
.lamp {
width: $lampSize;
height: $lampSize;
line-height: $lampSize;
background-color: #0e0e0e;
margin: 5px;
border-radius: 50%;
text-align: center;
color: gray;
.iconfont {
font-size: $lampSize - 10px;
font-weight: bolder;
}
}
</style>
可以在測驗頁面測驗:
<lamp direction="left" color="green"></lamp>
3.2 實作 lamp-group 組件
lamp-group 組件中容納了三個 lamp,分別是紅燈、黃燈、綠燈,
lamp-group.vue:
<template>
<div :>
<div >
<lamp :direction="direction" :color="status === Status.R ? status : Status.O" />
<lamp :direction="direction" :color="status === Status.Y ? status : Status.O" />
<lamp :direction="direction" :color="status === Status.G ? status : Status.O" />
</div>
</div>
</template>
<script lang="ts" setup>
import { defineProps, PropType } from 'vue'
import Lamp from './lamp.vue'
import { Direction, Status } from '@/common/traffic-lamp-common'
defineProps({
direction: {
type: String as PropType<Direction>,
required: true
},
status: {
type: String as PropType<Status>,
required: false,
default: Status.O
}
})
</script>
<style scoped lang="scss">
@import "~@/assets/scss/traffic-lamp-common.scss";
.lamp-group {
background-color: #777;
margin: 0 10px;
padding: 10px;
.wrapper {
background-color: #5d5d5d;
padding:5px;
}
}
.radius-left {
border-radius: $radius 0 0 $radius;
}
.radius-right {
border-radius: 0 $radius $radius 0;
}
</style>
可以在測驗頁面測驗該組件:
<lamp-group direction="right" status="green" />
3.3 實作 traffic-lamp 組件
traffic-lamp 組件容納三個 lamp-group,分別代表左轉、直行、右轉,其中屬性 status 要代表三個 group 的狀態,父組件在使用時可以用逗號分隔,在設計的時候,也可以將狀態拆分為三個屬性,每個方向對應一個狀態,
traffic-lamp.vue:
<template>
<div >
<lamp-group :direction="Direction.L" :status="statusList[0] || Status.O" />
<lamp-group :direction="Direction.C" :status="statusList[1] || Status.O" />
<lamp-group :direction="Direction.R" :status="statusList[2] || Status.O" />
</div>
</template>
<script lang="ts" setup>
import { computed, defineProps } from 'vue'
import LampGroup from './lamp-group.vue'
import { Status, Direction } from '@/common/traffic-lamp-common'
const props = defineProps({
status: {
type: String,
required: false,
default: ''
}
})
const statusList = computed(() => {
const list = props.status.split(',')
const remain = 3 - list.length
for (let i = 0; i < remain; i++) {
list.push(Status.O)
}
return list
})
</script>
<style scoped lang="scss">
.traffic-lamp {
display: flex;
}
</style>
可以在測驗頁面測驗該組件:
<traffic-lamp status="red,red"></traffic-lamp>
4 附加功能
到這里為止,交通燈功能就模擬實作完成了,切換交通燈紅綠燈狀態時,只需要改變 status 即可,
現在咱額外新增一個功能,新國標有 8 種狀態,咱就讓這 8 種狀態自動切換,
下列所有代碼都撰寫在測驗頁面中,在測驗頁面中使用 traffic-lamp 組件,
4.1 狀態陣列
在測驗頁面中定義 8 種狀態串列:
const { R, G, O } = Status
const statusList = [
`${R},${R},${R}`,
`${R},${R},${O}`,
`${G},${R},${R}`,
`${O},${R},${O}`,
`${R},${G},${R}`,
`${O},${G},${R}`,
`${R},${G},${O}`,
`${O},${G},${O}`
]
4.2 定義索引
在測驗頁面中定義遍歷狀態串列的索引:
const currentIndexRef = ref(0)
const currentStatus = computed(() => statusList[currentIndexRef.value])
在模板中動態設定 traffic-lamp 的 status 屬性:
<traffic-lamp :status="currentStatus"></traffic-lamp>
4.3 自動切換
在測驗頁面 onMounted 生命周期函式中,定時修改索引 currentIndexRef 的值,從而實作紅綠燈的自動切換:
onMounted(() => {
setInterval(() => {
currentIndexRef.value += 1
currentIndexRef.value = https://www.cnblogs.com/youyacoder/archive/2022/08/24/currentIndexRef.value % statusList.length
}, 1000)
})
4.4 文字描述
可以在紅綠燈下面添加是否可以通行的文字描述,
模板:
<traffic-lamp :status="currentStatus"></traffic-lamp>
<div >
<div :>{{getText(left)}}</div>
<div :>{{getText(center)}}</div>
<div :>{{getText(right)}}</div>
</div>
TS 代碼:
const left = computed(() => {
const list = currentStatus.value.split(',')
return list[0] === Status.O ? list[1] : list[0]
})
const center = computed(() => {
return currentStatus.value.split(',')[1] || Status.O
})
const right = computed(() => {
const list = currentStatus.value.split(',')
return list[2] === Status.R ? Status.R : Status.G
})
const getText = (status: string) => {
if (status === Status.G) {
return '可以通行'
}
if (status === Status.R) {
return '停車等待'
}
return ''
}
樣式:
<style scoped lang="scss">
@import "~@/assets/scss/traffic-lamp-common.scss";
.display {
width: 420px;
display: flex;
margin-top: 10px;
div {
flex: 1;
text-align: center;
}
}
</style>
運行如下:

\/ “程式員優雅哥”,今日學習到此結束,期待一箭三連(贊、藏、轉)~~~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/502664.html
標籤:其他
