Vue 3-150行代码实现新国标红绿灯效果案例
昨天刷视频,都是关于新国标红绿灯的,看大家议论纷纷,下班就用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 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>
可以在测试页面测试:
<lamp direction="left" color="green"></lamp>
3.2 实现 lamp-group 组件
lamp-group 组件中容纳了三个 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>
可以在测试页面测试该组件:
<lamp-group direction="right" status="green" />
3.3 实现 traffic-lamp 组件
traffic-lamp 组件容纳三个 lamp-group,分别代表左转、直行、右转。其中属性 status 要代表三个 group 的状态,父组件在使用时可以用逗号分隔。在设计的时候,也可以将状态拆分为三个属性,每个方向对应一个状态。
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>
可以在测试页面测试该组件:
<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 = 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>
运行如下:
\/ “程序员优雅哥”,今日学习到此结束,期待一箭三连(赞、藏、转)~~~
Vue 3-150行代码实现新国标红绿灯效果案例的更多相关文章
- java开发区块链只需150行代码
本文目的是通过java实战开发教程理解区块链是什么.将通过实战入门学习,用Java自学开发一个很基本的区块链,并在此基础上能扩展如web框架应用等.这个基本的java区块链也实现简单的工作量证明系统. ...
- 150行代码搭建异步非阻塞Web框架
最近看Tornado源码给了我不少启发,心血来潮决定自己试着只用python标准库来实现一个异步非阻塞web框架.花了点时间感觉还可以,一百多行的代码已经可以撑起一个极简框架了. 一.准备工作 需要的 ...
- 150行代码打造.net core生产力工具,你值得拥有
你是否在初学 .net core时,被依赖注入所折磨? 你是否在开发过程中,为了注入依赖而不停的在Startup中增加注入代码,而感到麻烦? 你是否考虑过或寻找过能轻松实现自动注入的组件? 如果有,那 ...
- jquery 20行代码实现简单轮播效果
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 150行JavaScript代码实现增强现实
增强现实技术(Augmented Reality,简称 AR),是一种实时地计算摄影机影像的位置及角度并加上相应图像.视频.3D模型的技术,这种技术的目标是在屏幕上把虚拟世界套在现实世界并进行互动.这 ...
- 150+行Python代码实现带界面的数独游戏
150行代码实现图形化数独游戏 Github地址,欢迎各位大佬们fork.star啥的,感谢: 今天闲着没事干,以前做过html+js版的数独,这次做个python版本的,界面由pygame完成,数独 ...
- jquery轮播图详解,40行代码即可简单解决。
我在两个月以前没有接触过html,css,jquery,javascript.今天我却在这里分享一篇技术贴,可能在技术大牛面前我的文章漏洞百出,也请斧正. 可以看出来,无论是div+css布局还是jq ...
- Android Studio 单刷《第一行代码》系列 02 —— 日志工具 LogCat
前情提要(Previously) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Andr ...
- Android Studio 单刷《第一行代码》系列 04 —— Activity 相关
前情提要(Previously) 本系列将使用 Android Studio 将<第一行代码>(书中讲解案例使用Eclipse)刷一遍,旨在为想入坑 Android 开发,并选择 Andr ...
随机推荐
- 关于VHDL中case语句多执行语句的书写方式(转载stackoverflow.com并做翻译汇总)
很多国内的教材对于case语句的讲解非常单一,比如: 1 [标号:]CASE 多值表达式 IS 2 WHEN 选择值 => 被赋值变量 <=赋值变量: 3 WHEN 选择值 => 被 ...
- 1.1 操作系统的第一个功能——虚拟化硬件资源 -《zobolの操作系统学习札记》
1.1 操作系统的第一个功能--虚拟化硬件资源 目录 1.1 操作系统的第一个功能--虚拟化硬件资源 问1:操作系统一般处于计算机系统的哪一个位置? 问2:管理硬件资源为什么要单独交给操作系统? 问3 ...
- React.js中JSX的原理与关键实现
在开始开发之前,我们需要创建一个空项目文件夹.安装 初始化 npm init -y 2.安装webpack相关依赖 npm install webpack webpack-cli -D 安装babel ...
- 手把手教学~基于element封装tree树状下拉框
在日常项目开发中,树状下拉框的需求还是比较常见的,但是element并没有这种组件以供使用.在这里,小编就基于element如何封装一个树状下拉框做个详细的介绍. 通过这篇文章,你可以了解学习到一个树 ...
- WPF开发随笔收录-报警闪烁效果实现
一.前言 工作中目前经手的项目是医疗相关的监护软件,所以会涉及到一些报警效果的实现,今天在这里就简单分享一下实现方式 二.正文 1.实现的方式比较的简单,就是通过一个Border控件,然后搭配Data ...
- Linux用户、组 管理
Linux安全模型 3A: Authentication:认证,验证用户身份 Authorization:授权,不同的用户设置不同权限 Accouting|Audition:审计 Linux用户: 管 ...
- Linux字符集和编码
计算机内部,所有信息最终都是一个二进制值形式存放 字符集 字符集:charset是character set的简写,即二进制和字符的对应关系,不关注最终的存储形式 编码 字符集编码:encoding是 ...
- Web思维导图实现的技术点分析(附完整源码)
简介 思维导图是一种常见的表达发散性思维的有效工具,市面上有非常多的工具可以用来画思维导图,有免费的也有收费的,此外也有一些可以用来帮助快速实现的JavaScript类库,如:jsMind.KityM ...
- c# 把网络图片http://....png 打包成zip文件
思路: 1.把网络图片下载到服务器本地. 2.读取服务器图片的文件流 3.使用zip帮助类,把图片文件流写进zip文件流. 4.如果是文件服务器,把zip文件流 推送文件服务器,生成zip的下载url ...
- mysql拆分字符串做条件查询
mysql拆分字符串作为查询条件 有个群友问一个问题 这表的ancestors列存放的是所有的祖先节点,以,分隔 例如我查询dept_id为103的所有祖先节点,现在我只有一个dept_id该怎么查 ...