昨天刷视频,都是关于新国标红绿灯的,看大家议论纷纷,下班就用150行代码通过Vue组件实践红绿模拟演示,视频也跟大家展示过了。今天接着更新图文版本,大家跟着优雅哥通过该案例实操模拟一下。
不过新国标红绿灯的设计,这个专业性、逻辑性、艺术性就是厉害,三个方向 * 三种颜色,玩转九宫格。大部分场景都可以不加思考就知道应该通行或者等待,只有某些情况下对应行驶方向的灯不亮时,才需要 if ... else ... 判断。优雅哥比较脑残,无论哪个方向:左转、直行、右转,如果灯都亮着,不就可以一眼看出能否通行了吗,对应方向红灯就停、绿灯就通行,这样是不是就可以不需要思考了?或许专家是为了省电吧,三个方向都亮灯太费电了。
后面得知,关于新国标红绿灯信息是误传,以上说辞纯属个人当时根据信息的一些看法,请大家不要误以为真。
现在来说说作为程序员,咱就用 Vue3 来模拟新国标红绿灯玩一玩。
组件化开发是我们一贯的风格。如何进行这个红绿灯组件的设计呢?

从上图可以看出我对新国标红绿灯的组件拆分。
lamp 代表每个灯,在上图中一共有9个灯,分别是左转三个颜色的灯、直行三个颜色的灯、右转三个颜色的灯。这 9 个灯的区别是颜色和内部的箭头,而内部的箭头与车辆行驶方向(左转、右转、直行)有关,故颜色和方向可定义为属性,由外部传递。
图中一共有三个 lamp-group,每个行驶方向的三个颜色的灯组成一个 lamp-group。同样的,lamp-group 有一个属性为方向,该属性表示左转、直行或右转。此外,每个 lamp-group 中最多只有一个灯亮,故可以定义一个属性为状态,表示这个 lamp-group 中哪个灯亮、或者都不亮。
traffic-lamp 表示整个新国标红绿灯。有三个 lamp-group 组成。整个红绿灯也需要一个状态属性,描述三个方向的 lamp-group 的状态。
在 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;
}
创建 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'
}
由于灯里面有左箭头、右箭头两个图标,故从 iconfont 上搜索并下载这两个图标,优雅哥采用 iconfont 的方式使用图标,资源文件位于 src/assets/iconfont 下。在 main.ts 中引入iconfont:
import '@/assets/iconfont/iconfont.css'
在 src/components 目录下创建目录 traffic-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>
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" />
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>
到这里为止,交通灯功能就模拟实现完成了,切换交通灯红绿灯状态时,只需要改变 status 即可。
现在咱额外新增一个功能,新国标有 8 种状态,咱就让这 8 种状态自动切换。
下列所有代码都编写在测试页面中。在测试页面中使用 traffic-lamp 组件。
在测试页面中定义 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}`
]
在测试页面中定义遍历状态列表的索引:
const currentIndexRef = ref(0)
const currentStatus = computed(() => statusList[currentIndexRef.value])
在模板中动态设置 traffic-lamp 的 status 属性:
<traffic-lamp :status="currentStatus"></traffic-lamp>
在测试页面 onMounted 生命周期函数中,定时修改索引 currentIndexRef 的值,从而实现红绿灯的自动切换:
onMounted(() => {
setInterval(() => {
currentIndexRef.value += 1
currentIndexRef.value = currentIndexRef.value % statusList.length
}, 1000)
})
可以在红绿灯下面添加是否可以通行的文字描述。
模板:
<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>
运行如下:

\/ “程序员优雅哥”,今日学习到此结束,期待一箭三连(赞、藏、转)~~~
如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby
在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru
我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的
几个月前,我读了一篇关于rubygem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:
我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur
前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来