Vue 3-150行代码实现新国标红绿灯效果案例

昨天刷视频,都是关于新国标红绿灯的,看大家议论纷纷,下班就用150行代码通过Vue组件实践红绿模拟演示,视频也跟大家展示过了。今天接着更新图文版本,大家跟着优雅哥通过该案例实操模拟一下。

不过新国标红绿灯的设计,这个专业性、逻辑性、艺术性就是厉害,三个方向 * 三种颜色,玩转九宫格。大部分场景都可以不加思考就知道应该通行或者等待,只有某些情况下对应行驶方向的灯不亮时,才需要 if … else … 判断。优雅哥比较脑残,无论哪个方向:左转、直行、右转,如果灯都亮着,不就可以一眼看出能否通行了吗,对应方向红灯就停、绿灯就通行,这样是不是就可以不需要思考了?或许专家是为了省电吧,三个方向都亮灯太费电了。
后面得知,关于新国标红绿灯信息是误传,以上说辞纯属个人当时根据信息的一些看法,请大家不要误以为真。

现在来说说作为程序员,咱就用 Vue3 来模拟新国标红绿灯玩一玩。

1 组件分析

组件化开发是我们一贯的风格。如何进行这个红绿灯组件的设计呢?

 Vue 3-150行代码实现新国标红绿灯效果案例

从上图可以看出我对新国标红绿灯的组件拆分。

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


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
})

@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;
  }
}

可以在测试页面测试:


3.2 实现 lamp-group 组件

lamp-group 组件中容纳了三个 lamp,分别是红灯、黄灯、绿灯。

lamp-group.vue


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
  }
})

@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;
}

可以在测试页面测试该组件:


3.3 实现 traffic-lamp 组件

traffic-lamp 组件容纳三个 lamp-group,分别代表左转、直行、右转。其中属性 status 要代表三个 group 的状态,父组件在使用时可以用逗号分隔。在设计的时候,也可以将状态拆分为三个属性,每个方向对应一个状态。

traffic-lamp.vue


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
})

.traffic-lamp {
  display: flex;
}

可以在测试页面测试该组件:


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 属性:


4.3 自动切换

在测试页面 onMounted 生命周期函数中,定时修改索引 currentIndexRef 的值,从而实现红绿灯的自动切换:

onMounted(() => {
  setInterval(() => {
    currentIndexRef.value += 1
    currentIndexRef.value = currentIndexRef.value % statusList.length
  }, 1000)
})

4.4 文字描述

可以在红绿灯下面添加是否可以通行的文字描述。

模板:


  {{getText(left)}}
  {{getText(center)}}
  {{getText(right)}}

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 ''
}

样式:


@import "~@/assets/scss/traffic-lamp-common.scss";
.display {
  width: 420px;
  display: flex;
  margin-top: 10px;

  div {
    flex: 1;
    text-align: center;
  }
}

运行如下:

 Vue 3-150行代码实现新国标红绿灯效果案例
\/ “程序员优雅哥”,今日学习到此结束,期待一箭三连(赞、藏、转)~~~

Original: https://www.cnblogs.com/youyacoder/p/16620988.html
Author: 程序员优雅哥(/同)
Title: Vue 3-150行代码实现新国标红绿灯效果案例

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/578501/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • JavaScript闭包

    <!doctype html> <html lang="en"> <head> <title>&#x95…

    Linux 2023年6月13日
    076
  • Redis 常见面试题(2020最新版)

    https://www.cnblogs.com/javazhiyin/p/13839357.html 概述 什么是Redis Redis(Remote Dictionary Ser…

    Linux 2023年5月28日
    0103
  • 阿里云函数-爱奇艺签到

    简介 是否支持多账号:是消息推送平台:PUSHPLUS 代码 -*- coding: utf8 -*- import requests,random,string,hashlib,…

    Linux 2023年6月7日
    081
  • python获取Windows硬件特征信息

    1.python pip安装WMI 并用pyinstaller编译出device_chk.exe 参考内容:https://blog.csdn.net/fengmm521/arti…

    Linux 2023年6月7日
    086
  • Emacs Lisp 入门

    ;; This gives an introduction to Emacs Lisp in 15 minutes (v0.2d);;;; 英文原作者: Bastien / @bz…

    Linux 2023年6月13日
    0104
  • MACOS Terminal终端:更改zsh模式到bash模式(切换shell)

    MACOS Terminal终端:更改zsh模式到bash模式(切换shell) 一、GUI界面切换: preferences… -> shell open wi…

    Linux 2023年5月28日
    0169
  • QT父类信号调用子类槽函数

    故事背景:我定义了一个QT父类,里面有自定义信号和槽函数,我在main函数定义父类指针指向子类对象,此时发信号,子类收不到,开始咱们的探险之路。。。 解决方案:根据加断点发现调用的…

    Linux 2023年6月13日
    079
  • Linux目录结构信息

    一、系统目录结构介绍 1.1 常见系统目录结构 Windows下: C:\windows D:\Program Files Linux下: /etc/sysconfig /usr/…

    Linux 2023年5月27日
    072
  • Java50个关键字之final

    1)final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖、类不可被继承(不能再派生出新的子类)。 final属性:被final修饰的变量不可变,由于不可变有两重含义,…

    Linux 2023年6月7日
    089
  • Redis info参数总结(转)

    可以看到,info的输出结果是分几块的,有Servers、Clients、Memory等等,通过info后面接这些参数,可以指定输出某一块数据。 我刚开始在Gentoo上装的默认版…

    Linux 2023年5月28日
    0119
  • Redis Sentinel实现的机制与原理详解

    Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案。实际上这意味着你可以使用Sentinel模式创建一个可以不用人为干预而应对各种故障的Redis部署。 它…

    Linux 2023年5月28日
    0114
  • [ Linux ] 设置服务器开机自启端口

    https://www.cnblogs.com/yeungchie/ 需要用到的工具: crontab iptables crontab.set SHELL=/bin/bash P…

    Linux 2023年6月7日
    0106
  • Flask 易错点

    1.With上下文管理器 常用: with open("file_name","wb") as f: f.write("hello…

    Linux 2023年6月8日
    082
  • Python 内置logging 使用详细讲

    logging 的主要作用 提供日志记录的接口和众多处理模块,供用户存储各种格式的日志,帮助调试程序或者记录程序运行过程中的输出信息。 logging 日志等级 logging 日…

    Linux 2023年6月7日
    077
  • win10安装redis

    下载地址:https://github.com/MicrosoftArchive/redis/releases 这个太慢了 https://github.com/ServiceSt…

    Linux 2023年5月28日
    0118
  • centos7 设置开机启动任务

    环境:centos7 需求:前两天调通的DNS server(bind/named)设置开机自启动 操作: 修改 /etc/rc.local 注意这个 rc.local 文件默认是…

    Linux 2023年6月6日
    0101
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球