Vue?實(shí)現(xiàn)新國(guó)標(biāo)紅綠燈效果實(shí)例詳解
引言
昨天刷視頻,都是關(guān)于新國(guó)標(biāo)紅綠燈的,看大家議論紛紛,下班就用150行代碼通過(guò)Vue組件實(shí)踐紅綠模擬演示,視頻也跟大家展示過(guò)了。今天接著更新圖文版本,大家跟著優(yōu)雅哥通過(guò)該案例實(shí)操模擬一下。
不過(guò)新國(guó)標(biāo)紅綠燈的設(shè)計(jì),這個(gè)專業(yè)性、邏輯性、藝術(shù)性就是厲害,三個(gè)方向 * 三種顏色,玩轉(zhuǎn)九宮格。
大部分場(chǎng)景都可以不加思考就知道應(yīng)該通行或者等待,只有某些情況下對(duì)應(yīng)行駛方向的燈不亮?xí)r,才需要 if ... else ... 判斷。優(yōu)雅哥比較腦殘,無(wú)論哪個(gè)方向:左轉(zhuǎn)、直行、右轉(zhuǎn),如果燈都亮著,不就可以一眼看出能否通行了嗎,對(duì)應(yīng)方向紅燈就停、綠燈就通行,這樣是不是就可以不需要思考了?或許專家是為了省電吧,三個(gè)方向都亮燈太費(fèi)電了。 后面得知,關(guān)于新國(guó)標(biāo)紅綠燈信息是誤傳,以上說(shuō)辭純屬個(gè)人當(dāng)時(shí)根據(jù)信息的一些看法,請(qǐng)大家不要誤以為真。
現(xiàn)在來(lái)說(shuō)說(shuō)作為程序員,咱就用 Vue3 來(lái)模擬新國(guó)標(biāo)紅綠燈玩一玩。
1 組件分析
組件化開(kāi)發(fā)是我們一貫的風(fēng)格。如何進(jìn)行這個(gè)紅綠燈組件的設(shè)計(jì)呢?

從上圖可以看出我對(duì)新國(guó)標(biāo)紅綠燈的組件拆分。
1.1 lamp
lamp 代表每個(gè)燈,在上圖中一共有9個(gè)燈,分別是左轉(zhuǎn)三個(gè)顏色的燈、直行三個(gè)顏色的燈、右轉(zhuǎn)三個(gè)顏色的燈。這 9 個(gè)燈的區(qū)別是顏色和內(nèi)部的箭頭,而內(nèi)部的箭頭與車輛行駛方向(左轉(zhuǎn)、右轉(zhuǎn)、直行)有關(guān),故顏色和方向可定義為屬性,由外部傳遞。
1.2 lamp-group
圖中一共有三個(gè) lamp-group,每個(gè)行駛方向的三個(gè)顏色的燈組成一個(gè) lamp-group。同樣的,lamp-group 有一個(gè)屬性為方向,該屬性表示左轉(zhuǎn)、直行或右轉(zhuǎn)。此外,每個(gè) lamp-group 中最多只有一個(gè)燈亮,故可以定義一個(gè)屬性為狀態(tài),表示這個(gè) lamp-group 中哪個(gè)燈亮、或者都不亮。
1.3 traffic-lamp
traffic-lamp 表示整個(gè)新國(guó)標(biāo)紅綠燈。有三個(gè) lamp-group 組成。整個(gè)紅綠燈也需要一個(gè)狀態(tài)屬性,描述三個(gè)方向的 lamp-group 的狀態(tài)。
2 全局文件定義
2.1 樣式變量
在 src/assets/ 中創(chuàng)建目錄 scss,并在該目錄下創(chuàng)建樣式變量文件 traffic-lamp-common.scss,在該文件中定義紅黃綠顏色、間距等常見(jiàn)樣式,便于全局保持一致。由于咱 demo 較小,將 scss 變量與通用樣式定義在一起就可以了,如果在正式開(kāi)發(fā)中,要遵守 CSS 架構(gòu)規(guī)范,無(wú)論是 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 常量定義
創(chuàng)建 src/common/traffic-lamp-common.ts,在該文件中定義兩個(gè)枚舉類,分別是行駛方向(左、直、右)和燈的狀態(tài),O - off 表示燈不亮。
export enum Direction {
L = 'left',
C = 'center',
R = 'right'
}
export enum Status {
R = 'red',
Y = 'yellow',
G = 'green',
O = 'off'
}
2.3 導(dǎo)入資源
由于燈里面有左箭頭、右箭頭兩個(gè)圖標(biāo),故從 iconfont 上搜索并下載這兩個(gè)圖標(biāo),優(yōu)雅哥采用 iconfont 的方式使用圖標(biāo),資源文件位于 src/assets/iconfont 下。在 main.ts 中引入iconfont:
import '@/assets/iconfont/iconfont.css'
3 組件開(kāi)發(fā)
在 src/components 目錄下創(chuàng)建目錄 traffic-lamp,上面分析的三個(gè)組件就在該目錄下開(kāi)發(fā)。
3.1 實(shí)現(xiàn) lamp 組件
lamp.vue:
<template>
<div class="lamp" :class="colorClass">
<span v-if="direction === Direction.L" class="iconfont icon-left"></span>
<span v-if="direction === Direction.R" class="iconfont icon-right"></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>
可以在測(cè)試頁(yè)面測(cè)試:
<lamp direction="left" color="green"></lamp>
3.2 實(shí)現(xiàn) lamp-group 組件
lamp-group 組件中容納了三個(gè) lamp,分別是紅燈、黃燈、綠燈。
lamp-group.vue:
<template>
<div class="lamp-group" :class="{
'radius-left': direction === Direction.L,
'radius-right': direction === Direction.R}">
<div class="wrapper">
<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>
可以在測(cè)試頁(yè)面測(cè)試該組件:
<lamp-group direction="right" status="green" />
3.3 實(shí)現(xiàn) traffic-lamp 組件
traffic-lamp 組件容納三個(gè) lamp-group,分別代表左轉(zhuǎn)、直行、右轉(zhuǎn)。其中屬性 status 要代表三個(gè) group 的狀態(tài),父組件在使用時(shí)可以用逗號(hào)分隔。在設(shè)計(jì)的時(shí)候,也可以將狀態(tài)拆分為三個(gè)屬性,每個(gè)方向?qū)?yīng)一個(gè)狀態(tài)。
traffic-lamp.vue:
<template>
<div class="traffic-lamp">
<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>
可以在測(cè)試頁(yè)面測(cè)試該組件:
<traffic-lamp status="red,red"></traffic-lamp>
4 附加功能
到這里為止,交通燈功能就模擬實(shí)現(xiàn)完成了,切換交通燈紅綠燈狀態(tài)時(shí),只需要改變 status 即可。
現(xiàn)在咱額外新增一個(gè)功能,新國(guó)標(biāo)有 8 種狀態(tài),咱就讓這 8 種狀態(tài)自動(dòng)切換。
下列所有代碼都編寫(xiě)在測(cè)試頁(yè)面中。在測(cè)試頁(yè)面中使用 traffic-lamp 組件。
4.1 狀態(tài)數(shù)組
在測(cè)試頁(yè)面中定義 8 種狀態(tài)列表:
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 定義索引
在測(cè)試頁(yè)面中定義遍歷狀態(tài)列表的索引:
const currentIndexRef = ref(0) const currentStatus = computed(() => statusList[currentIndexRef.value])
在模板中動(dòng)態(tài)設(shè)置 traffic-lamp 的 status 屬性:
<traffic-lamp :status="currentStatus"></traffic-lamp>
4.3 自動(dòng)切換
在測(cè)試頁(yè)面 onMounted 生命周期函數(shù)中,定時(shí)修改索引 currentIndexRef 的值,從而實(shí)現(xiàn)紅綠燈的自動(dòng)切換:
onMounted(() => {
setInterval(() => {
currentIndexRef.value += 1
currentIndexRef.value = currentIndexRef.value % statusList.length
}, 1000)
})
4.4 文字描述
可以在紅綠燈下面添加是否可以通行的文字描述。
模板:
<traffic-lamp :status="currentStatus"></traffic-lamp>
<div class="display">
<div :class="left">{{getText(left)}}</div>
<div :class="center">{{getText(center)}}</div>
<div :class="right">{{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>
運(yùn)行如下:

以上就是Vue 實(shí)現(xiàn)新國(guó)標(biāo)紅綠燈效果實(shí)例詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue 新國(guó)標(biāo)紅綠燈的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Vue下拉框加分頁(yè)搜索功能的實(shí)現(xiàn)方法
- vue中利用pinyin-pro純前端實(shí)現(xiàn)拼音的模糊搜索功能
- Vue使用高德地圖選點(diǎn)定位搜索定位功能實(shí)現(xiàn)
- vue 實(shí)現(xiàn)模糊檢索并根據(jù)其他字符的首字母順序排列
- vue input輸入框關(guān)鍵字篩選檢索列表數(shù)據(jù)展示
- vue2.0實(shí)現(xiàn)移動(dòng)端的輸入框?qū)崟r(shí)檢索更新列表功能
- 基于go+vue實(shí)現(xiàn)的golang每日新聞數(shù)據(jù)瀏覽與檢索平臺(tái)(推薦)
- vue實(shí)現(xiàn)文字檢索時(shí)候?qū)⑺阉鲀?nèi)容標(biāo)紅功能
相關(guān)文章
uni-app自定義導(dǎo)航欄按鈕|uniapp仿微信頂部導(dǎo)航條功能
這篇文章主要介紹了uni-app自定義導(dǎo)航欄按鈕|uniapp仿微信頂部導(dǎo)航條,需要的朋友可以參考下2019-11-11
vue實(shí)現(xiàn)一個(gè)矩形標(biāo)記區(qū)域(rectangle marker)的方法
這篇文章主要介紹了vue實(shí)現(xiàn)一個(gè)矩形標(biāo)記區(qū)域 rectangle marker的方法,幫助大家實(shí)現(xiàn)區(qū)域標(biāo)記功能,感興趣的朋友可以了解下2020-10-10
Vue導(dǎo)入excel表,導(dǎo)入失敗的數(shù)據(jù)自動(dòng)下載
本文詳細(xì)講解了Vue導(dǎo)入excel表,導(dǎo)入失敗的數(shù)據(jù)自動(dòng)下載的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11
基于Vue3+WebSocket實(shí)現(xiàn)實(shí)時(shí)文件傳輸監(jiān)控系統(tǒng)
WebSocket是一種在客戶端和服務(wù)器之間進(jìn)行雙向通信的網(wǎng)絡(luò)協(xié)議,它通過(guò)建立持久性的、全雙工的連接,允許服務(wù)器主動(dòng)向客戶端發(fā)送數(shù)據(jù),本文小編給大家介紹了基于Vue3+WebSocket實(shí)現(xiàn)實(shí)時(shí)文件傳輸監(jiān)控系統(tǒng),需要的朋友可以參考下2025-03-03
vue?當(dāng)中組件之間共享數(shù)據(jù)的實(shí)現(xiàn)方式
這篇文章主要介紹了vue?當(dāng)中組件之間共享數(shù)據(jù)的實(shí)現(xiàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-10-10
詳解Vue3.0 + TypeScript + Vite初體驗(yàn)
這篇文章主要介紹了詳解Vue3.0 + TypeScript + Vite初體驗(yàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
vue監(jiān)聽(tīng)滾動(dòng)條頁(yè)面滾動(dòng)動(dòng)畫(huà)示例代碼
Vue是一套用于構(gòu)建用戶界面的漸進(jìn)式框架,與其它大型框架不同的是,Vue?被設(shè)計(jì)為可以自底向上逐層應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于vue監(jiān)聽(tīng)滾動(dòng)條頁(yè)面滾動(dòng)動(dòng)畫(huà)的相關(guān)資料,需要的朋友可以參考下2023-06-06
vue/cli3.0腳手架部署到nginx時(shí)頁(yè)面空白的問(wèn)題及解決
這篇文章主要介紹了vue/cli3.0腳手架部署到nginx時(shí)頁(yè)面空白的問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-10-10

