昨天在数码论坛看了了一篇文章,是一个发烧友制作的51单片机模拟红绿灯的。51虽然应用广泛,但是现在有更多的物联网开发板,尤其是支持javascript的,更易于开发,于是我想是不是可以在网页里用js模拟一个红绿灯切换。

这次主要是分享给像我一样正在关注和初学javascript的朋友,通过详细的描述写作过程,了解如何用原生js的定时器,以及动态的更改网页元素样式:

  • window.setTimeout(functionName,time)
  • document.getElementById('XX').className='XXXX'

关于js的一些基本知识就不再详细讲解了,如果有问题可以留言或者私信交流。

PS:最终的网页文件我已经上传到网盘,有获取方式。

红绿灯时我们最容易接触到的事物,无论是晴天下雨,它都在默默工作者,现如今已经有可以根据车流量自动控制的智能红绿灯,这背后是科技的发展是生产力的提升是人类智慧的伟大表现。

js建筑图代表什么(探索中心红绿灯的秘密)(1)

2014年,Marvell推出支持Javascript的物联网设备开发套件Kinoma Create:

js建筑图代表什么(探索中心红绿灯的秘密)(2)

我手上暂时没有能用的开发板,所以就用浏览器写一个在网页里的模拟。首先声明本人非专业科班出身的程序员,从来没有上过任何编程相关的课程。平时都是看文字和案例自学,浪迹各种论坛,很多知识点都没能GET到,似懂非懂,所以下面有什么错误和有瑕疵的地方请多多指正:-)

先看一下最终的效果图:

js建筑图代表什么(探索中心红绿灯的秘密)(3)

这是一个小镇,中央大道的路口,红绿灯默默的在工作,那它能来回切换的“秘密”到底是什么?

js建筑图代表什么(探索中心红绿灯的秘密)(4)

专业的灯控演示图,这不是我们本章探讨的

设想一下,这是一个小镇,东西与南北两条路,四角有四个社区,这些都可以用div在网页结合css样式表现出来,中央红绿灯的切换接下来就靠我们的js代码来控制了。

js建筑图代表什么(探索中心红绿灯的秘密)(5)

首先,要新建一个文件,文件名任意,后缀名html,用编辑器打开后就可以编辑了。

理论上,更友好的操作是把html css js分开编写,这里为了方便分享我们把样式和脚本都写到一个文件里了。

你可以用任何文本编辑器编辑,包括记事本,但是还是建议使用专业的工具,一是涉及到文件编码,编码不对可能导致显示乱码;二是有关键字高亮显示;三是快捷的文本缩进,有利于阅读;四是可以在编辑过程中直接同步预览效果等等。

下面分别是几种不同编辑器对同一段HTML代码显示的效果:

js建筑图代表什么(探索中心红绿灯的秘密)(6)

微软家的 Visual Studio Code

js建筑图代表什么(探索中心红绿灯的秘密)(7)

Adobe出品的编辑器Brackets

js建筑图代表什么(探索中心红绿灯的秘密)(8)

收费但是确实强悍的sublime text

js建筑图代表什么(探索中心红绿灯的秘密)(9)

这个都认识,灵魂程序员用的记事本

js建筑图代表什么(探索中心红绿灯的秘密)(10)

绿色轻便简洁但不简单的notepad2

js建筑图代表什么(探索中心红绿灯的秘密)(11)

老牌网页编辑器dreamware

js建筑图代表什么(探索中心红绿灯的秘密)(12)

任何文件都可以打开的UltraEdit

以上几款个人强力推荐:Visual Studio Code 和 sublime text,扩展很丰富,配合git可以说走遍天下不用愁。至于dreamware,虽然也很强大,有些方面还是让人比较抵触,比如消耗的系统资源比较多,选文字容易错位。


html是基于XML格式的描述文件,所以我们先把基本的内容输入。使用Visual Studio Code在新建html文件后,可以输入英文!然后按下Tab键自动填充。

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> </head> <body> </body> </html>

js建筑图代表什么(探索中心红绿灯的秘密)(13)


改一下头部定义,删除不必要的内容。

因为我们要在一个文件里写脚本和样式,除了建立一个<div>放置元素外分别插入<style><script>两个标签。

js建筑图代表什么(探索中心红绿灯的秘密)(14)

设置最外层的div样式为‘main’,并且修改对应的css,这层div相当于一片土地,再在其中插入一个div,样式为‘town’,这是承载小镇所有建筑的田园。

js建筑图代表什么(探索中心红绿灯的秘密)(15)

在浏览器预览一下效果:

js建筑图代表什么(探索中心红绿灯的秘密)(16)

我们再在town下面插入四个div,代表四角的社区,这样就形成一个十字形的马路了。这里要修改它们的定位模式position:relative,然后通过left、top等分布在四角。

js建筑图代表什么(探索中心红绿灯的秘密)(17)

  • town内部所有div都设置为absolute定位

.town > div{ position: absolute; }

js建筑图代表什么(探索中心红绿灯的秘密)(18)

js建筑图代表什么(探索中心红绿灯的秘密)(19)

看,我们现在有个十字路口了。

为了小镇的交通安全,我们给南北和东西两条路分拨画上车道。

js建筑图代表什么(探索中心红绿灯的秘密)(20)

js建筑图代表什么(探索中心红绿灯的秘密)(21)

js建筑图代表什么(探索中心红绿灯的秘密)(22)

嗯,现在人们可以双向分开形势了,不过路口还不行,平常我们的路口是空白的。

我们加一个路口。

js建筑图代表什么(探索中心红绿灯的秘密)(23)

js建筑图代表什么(探索中心红绿灯的秘密)(24)

js建筑图代表什么(探索中心红绿灯的秘密)(25)

路有了,人多了,车多了,那必须得上红绿灯。

建立四个div代表灯箱。

js建筑图代表什么(探索中心红绿灯的秘密)(26)

js建筑图代表什么(探索中心红绿灯的秘密)(27)

js建筑图代表什么(探索中心红绿灯的秘密)(28)

然后给每个灯箱的div里面装上三个灯:红黄绿

js建筑图代表什么(探索中心红绿灯的秘密)(29)

js建筑图代表什么(探索中心红绿灯的秘密)(30)

分别写好开灯和关灯的样式,通过div背景色实现。另外用到了css圆角属性实现圆形的DIV。

js建筑图代表什么(探索中心红绿灯的秘密)(31)

js建筑图代表什么(探索中心红绿灯的秘密)(32)

最后网页部分我们还要加上控制按钮

js建筑图代表什么(探索中心红绿灯的秘密)(33)

js建筑图代表什么(探索中心红绿灯的秘密)(34)


静态的布局结束,重点来了,js部分。

脚本每一部分我都写了详细的注释,直接贴上来给大家看。

<script> var green=0,yellow=1,red=2; var a,b,t; //t用来记录用户输入的绿灯时长设定 var traffic={}; //把路口红绿灯这件事设定为一个对象,所有的操作都基于名为“traffic”的对象,它好比是路口的灯控箱,有开关,有电还能人为的设定等等 traffic.x={}; //X相当于连接东西方向的线路,控制着左右两个灯,y同理控制着南北方向。上北下南 //把每个灯组的红黄绿都加到这个对象下面,左右两个绿灯同时控制 traffic.x[green]=[]; traffic.x[green].push(document.getElementById('lightW').children[green]); traffic.x[green].push(document.getElementById('lightE').children[green]); traffic.x[yellow]=[]; traffic.x[yellow].push(document.getElementById('lightW').children[yellow]); traffic.x[yellow].push(document.getElementById('lightE').children[yellow]); traffic.x[red]=[]; traffic.x[red].push(document.getElementById('lightW').children[red]); traffic.x[red].push(document.getElementById('lightE').children[red]); //y控制南北方向的灯 traffic.y={} traffic.y[green]=[] traffic.y[green].push(document.getElementById('lightN').children[green]); traffic.y[green].push(document.getElementById('lightS').children[green]); traffic.y[yellow]=[]; traffic.y[yellow].push(document.getElementById('lightN').children[yellow]); traffic.y[yellow].push(document.getElementById('lightS').children[yellow]); traffic.y[red]=[]; traffic.y[red].push(document.getElementById('lightN').children[red]); traffic.y[red].push(document.getElementById('lightS').children[red]); //灯连接上了,下面开始加入方法,也就是控制灯的开关 traffic.pass=function(e){//这里设定通行方向的灯,e参数为要控制的方向,东西是x,南北是Y if(e===this.x){//分开控制,一个开另一个方向就是关 this.setpass(this.x);this.setbreak(this.y);//这里之前设定反了 }else{ this.setpass(this.y);this.setbreak(this.x); } } traffic.setpass=function(e){//开灯,绿灯亮,黄灯红灯灭,通行 e[green][0].className='greenON'; e[green][1].className='greenON'; e[yellow][0].className='yellowOFF'; e[yellow][1].className='yellowOFF'; e[red][0].className='redOFF'; e[red][1].className='redOFF'; } traffic.setbreak=function(e){//关灯,绿灯黄灯灭,红灯亮,禁行 e[green][0].className='greenOFF'; e[green][1].className='greenOFF'; e[yellow][0].className='yellowOFF'; e[yellow][1].className='yellowOFF'; e[red][0].className='redON'; e[red][1].className='redON'; } /*设定一条完整的亮灯流程 最简单的模式就是:绿灯-闪绿灯-黄灯-红灯 所以按照上面方法设定定时器就可以了 setTimeout(方法,时间/单位毫秒) */ traffic.greenTime=function(){//绿灯时间 traffic.timer=window.setTimeout(traffic.greenFlashON,t*1000);//t为用户设定的绿灯时间,这里注意settimeout单位是毫秒 } traffic.greenFlashON=function(){//时间到了绿灯闪一下,这时候先灭灯 //等下再写灯的开关等等 //记得刚才的a为通行方向,这里暂时关一下绿灯制造闪烁 a[green][0].className='greenOFF'; a[green][1].className='greenOFF'; traffic.timer=window.setTimeout(traffic.greenFlashOFF,700);//闪烁绿灯 绿灯灭0.7秒 } traffic.greenFlashOFF=function(){//灭完接着打开绿灯 a[green][0].className='greenON'; a[green][1].className='greenON'; traffic.timer=window.setTimeout(traffic.yellowTime,1300);//闪烁完以后再亮1.3秒 } traffic.yellowTime=function(){//绿灯亮完最后一段时间后就是黄灯,这时候红绿都是灭的 a[yellow][0].className='yellowON'; a[yellow][1].className='yellowON'; a[green][0].className='greenOFF'; a[green][1].className='greenOFF'; traffic.timer=window.setTimeout(traffic.changeLight,1000);//最后黄灯1秒 } traffic.changeLight=function(){//黄灯完了以后就切换方向 //判断a是a哪个方向,然后交换一下 if(a===traffic.x){ a=traffic.y; b=traffic.x; }else{ a=traffic.x; b=traffic.y;//其实b一直没用到,可以去除掉 } traffic.pass(a); traffic.greenTime();//切换完方向又开始新一轮亮灯循环 } //先给两个按钮的单击事件写好方法 traffic.start=function(){//单击开始 this.stop(); //开始前先停止一下,防止用户多次单击开始按钮,重复单击也会先清除之前状态,重新开始 t=parseInt(document.getElementById('times').value); //获取文本框输入的时间,一定要转化为整数,用户可能输入任何内容,不转导致t可能为无效的参数 //判断一下得到的t是不是NaN,是不是可用 if(isNaN(t)){t=4;} //为了更好的体验,时间约束在2-10秒之间 if(t<2){t=2;} if(t>10){t=10;} //将t值填回文本框 document.getElementById('times').value=t; //因为用到了定时器,使用中一些变量作为参数要注意范围,在js所有异步操作中都要注意 //这里要用到之前声明的a b两个变量来指向当前通行方向和禁行方向 a=this.y; b=this.x; this.pass(a); //初始化完毕开始切入亮灯流程 this.greenTime(); } traffic.stop=function(){//单击结束,结束的时候一定要清除定时器 if(this.hasOwnProperty('timer')){ window.clearTimeout(this.timer); delete this.timer; } this.pass(this.y);//设定为南北通行,然后关闭所有灯 this.y[green][0].className='greenOFF'; this.y[green][1].className='greenOFF'; this.x[red][0].className='redOFF'; this.x[red][1].className='redOFF'; //四个方向灯都是灭的,不工作中 } //网页加载完首先执行stop方法,复位灯的状态 traffic.stop(); console.log('星星糖老师'); </script>

完整的文件请关注“星星糖老师”后发私信“网页里的红绿灯”获取分享链接。

,