内容简介:JavaScript总算入门了,复杂的就先不来了,今儿牛刀小试,先来一个系统同步的时钟效果,只用到最简单的获取系统时间的函数。因为学习是需要正反馈的,否则总也看不到效果,难免失了深入下去的兴趣。在之前的一篇专栏文章为了避免复杂的时钟图层太多的干扰,所以先来一个最最基础的版本,一个圆代表底盘,三个直线分别代表时针分针秒针,嗯,或者你可以称之为极简主义(MUJI风?Maybe)。既然是基础图形,那可以不用借助Ai,直接手动码出来就可以了。DOM部分(以800*600的画布为例,原点为(400,300))
JavaScript总算入门了,复杂的就先不来了,今儿牛刀小试,先来一个系统同步的时钟效果,只用到最简单的获取系统时间的函数。因为学习是需要正反馈的,否则总也看不到效果,难免失了深入下去的兴趣。在之前的一篇专栏文章 《利用CSS3的animation step属性实现wifi动画》 的末尾,曾经做过一个时钟,当时鉴于JS空白,最终虽然也实现了时钟效果,但却无法做到与系统时间同步。今次,就来做一个可与当前时间完全一致的时钟,并一步步实现从简陋到豪华的华丽变身。
1. 基础版,先实现效果
为了避免复杂的时钟图层太多的干扰,所以先来一个最最基础的版本,一个圆代表底盘,三个直线分别代表时针分针秒针,嗯,或者你可以称之为极简主义(MUJI风?Maybe)。既然是基础图形,那可以不用借助Ai,直接手动码出来就可以了。
DOM部分(以800*600的画布为例,原点为(400,300))
<!--圆形底盘--> <circle class="base" cx="400" cy="300" r="200" /> <!--长度为180的秒针--> <line class="pointer" id="second" x1="400" y1="300" x2="400" y2="120"/> <!--长度为140的分针--> <line class="pointer" id="minute" x1="400" y1="300" x2="400" y2="160"/> <!--长度为80的时针--> <line class="pointer" id="hour" x1="400" y1="300" x2="400" y2="220"/> 复制代码
CSS部分
<style type="text/css"> /* 圆形底盘 */ .base{stroke:#000000;stroke-width:4; fill:#FFFFFF} /* 指针公用描边样式 */ .pointer{opacity:0.5;fill:none;stroke:#000000;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:10;} /* 描边粗为6的秒针 */ #second{stroke-width:6;} /* 描边粗为12的分针 */ #minute{stroke-width:12;} /* 描边粗为18的时针 */ #hour{stroke-width:18;} </style> 复制代码
自然,这个最终的样子不是那么美,现在所有的指针都指向一个初始位置,即零时。
2.获取当前时间在SVG图形中体现
在此篇文章之前,一直玩的都是SVG+CSS3动画,那这里要啰嗦一下了。SVG毕竟只是一种图形绘制方法,支持CSS控制样式,但和控制交互的JS并无半点关联,既然要用JavaScript的函数及操作,所以,这里要做的第一步,就是把上一步创建的SVG图形像普通图片一样,整个一股脑儿的塞到html文件的body部分中。但这里SVG与普通图片相比,最大的优势是里面的标签元素可以被获取到并改变,往下看便知。在实际应用的过程中,要把SVG文件和JavaScript以引入的形式使用,这里为了方便,暂时不做剥离。
<!DOCTYPE html> <html lang="en"> <svg> …… SVG部分 </svg> </html> 复制代码
获取当前时间的函数很简单
<script> var dt=new Date(); //获取小时 var hour=dt.getHours(); //获取分 var minute=dt.getMinutes(); //获取秒 var second=dt.getSeconds(); </script> 复制代码
下面要做的是,把返回的时间在时钟上正确的映射,也就是说把旋转的度数与时间一一对应。360度对应12个小时,60分钟,60秒,就相应得出1hour→30度,1minute→6度,1second→6度的关系。为了方便使用,我把以上JS改了一下,直接改成度数值。
//小时对应的旋转度数 var hourDeg=dt.getHours()*30; //分钟对应的旋转度数 var minuteDeg=dt.getMinutes()*6; //秒对应的旋转度数 var secondDeg=dt.getSeconds()*6; 复制代码
CSS3里支持基本的旋转变形的属性,transform:rotate(相应度数),所以这里定义一个函数来给指针增加类样式,旋转的度数为上面获取到的当前时间对应的旋转度数。
//定义同步时间的函数 function syn(){ //给时针追加旋转变形的类样式 $("hour").style.cssText="transform:rotate("+hourDeg+"deg);"; //给分针追加旋转变形的类样式 $("minute").style.cssText="transform:rotate("+minuteDeg+"deg);"; //给秒针追加旋转变形的类样式 $("second").style.cssText="transform:rotate("+secondDeg+"deg);"; } 复制代码
这里还有一个和旋转变形关系极为密切的属性,旋转的原点 transform-origin ,因为是三种指针的共用属性值,所以我把旋转原点的定义 transform-origin:400px 300px 直接追加到了pointer类样式中。
为了测试是否好用,我让系统的时间暂时在窗口显示。
当调用这个函数时,可以看到当前时间与SVG图形中的时针分针秒针是完全对应的。
3.让时钟不停歇的动起来
其实上面的效果实现后,会一丢丢javascript的小伙伴已经知道了如何让时钟不停歇的动起来了。那就是定时器功能。只要设置每秒触发一次定时器就可以了。
//定义获取当前时间的函数 function timeId(){ var dt=new Date(); var hourDeg=dt.getHours()*30; var minuteDeg=dt.getMinutes()*6; var secondDeg=dt.getSeconds()*6; $("hour").style.cssText="transform:rotate("+hourDeg+"deg);"; $("minute").style.cssText="transform:rotate("+minuteDeg+"deg);"; $("second").style.cssText="transform:rotate("+secondDeg+"deg);"; } //定时器启动前先调用一次函数 timeId(); //定义每秒触发一次的定时器 setInterval(timeId, 1000); 复制代码
这样的话,就得到了一枚丑丑的,但是可以与当前时间同步的时钟。 但是,这里有个小问题, 因为返回的系统时间是整数值,对于秒针而言,一格格的跳着走没什么问题,但对于分针尤其是时针而言,到了整点再跳一格,显然是与现实世界中的时钟不符的。 比如08:59:59在下一秒09:00:00时,时针会从8大幅度的跳向9。因为我的表盘没有指针,所以看上去并不是那么明显。但从截取的GIF中可以看到明显的分针从42跳到43的效果。
以时针为例,解决思路很简单,只需要把分钟返回的数值换算成时针相应的度数,与时针对应的度数相加即可。60minutes→1hour→30度,即1minute→0.5度。 每1分钟,时针增加0.5度 。同理, 每1秒钟,分针增加0.1度 。于是我把原来定义的时针和分针的旋转变形角度,改成了下面这种
//时针度数修正,增加分针对应的度数 var hourDeg=dt.getHours()*30 + dt.getMinutes()*0.5; //分针度数修正,增加秒针对应的度数 var minuteDeg=dt.getMinutes()*6+dt.getSeconds()*0.1; 复制代码
按接近整点截了一段动图,看一下效果
实现了平滑过渡。这种方法的实现,其实并没有用到CSS3的动画属性,只用到了旋转变形属性。codepen附上全部源码 base template of SVG+javascript clock4.扔掉定时器,使用animation属性
不要急不要急,虽然上面完成了一个完全同步的时钟效果,但我们知道CSS3的 animation 属性是很强大的,结合 @keyframes 动画规则定义,是可以实现旋转效果的。在上面的实现思路中,因为每一秒完成一次旋转变形,因此并没有用到animation属性,下面就来试一试,如果不用定时器,如何实现这种效果。
先来看一下,如果是普通的旋转动画,不考虑动态的起始位置的话,定义的秒针的动画规则及animation属性的方法如下:
/*定义动画规则,旋转360度*/ @keyframes second{ 0%{transform:rotate(0deg)} 100%{transform:rotate(360deg)} } /*定义秒针的旋转动画属性,360度需要时间60秒*/ .second{animation:second linear 60s infinite} 复制代码
这里只需要解决一个问题,就是 0%关键帧对应的初始旋转角度的问题 。0%的确认后,100%的只需要增加360度即可。问题难就难在javascript并不能把变量值传进去来改变CSS的属性,但好在可以通过javascrpt重写CSS属性值。这里实现的思路有些麻烦,我贴上后逐句解释。
以秒针为例,DOM结构中,增加类属性的定义
<line class="pointer second" id="second" x1="400" y1="300" x2="400" y2="120"/>
CSS样式中仅保留second动画属性的定义
.second{animation:second linear 60s infinite}
但动画规则@keyframes通过以下方式实现:
- javascript创建一个新的CSS样式标签,<style type="text/css">……</style>
- 把规则作为内容写入新的样式标签中
- 把新的样式标签追加进去
//创建新的CSS style标签 var style = document.createElement("style"); style.type = "text/css"; //创建可以接受变量参数的动画规则 //初始关键帧为分针对应的角度 //结束关键帧为分针对应的角度 var keyFrames = "@keyframes second {\ 0% {transform: rotate("+secondDeg+"deg);}\ 100%{transform:rotate("+(secondDeg+360)+"deg)}}"; //把动画规则的内容写入新创建的style标签中 style.innerHTML = keyFrames; //把新的style标签作为svg的子元素追加进去 document.getElementsByTagName("svg")[0].appendChild(style); 复制代码
现在,只观察秒针,看看这种方法是不是可行。 f)
success!
通过这种方法,成功的把动态动画规则写入了CSS样式中。秒针的没有问题,那么分针和时针就是水到渠成的问题了。这里为了简化代码,封装了一个函数,把 动画规则的名称 和 初始的度数作为该函数的参数。
//创建一个新的CSS style标签 var style = document.createElement("style"); style.type = "text/css"; //定义一个新的style标签内容的函数,动画规则名称和初始度数作为参数 function newKeyFrames(name,degree){ var keyFrames = "@keyframes "+name+" {\ 0% {transform: rotate("+degree+"deg);}\ 100%{transform:rotate("+(degree+360)+"deg)}}"; //因为是新的style标签内容中不断增加新定义的动画规则,所以改成+= style.innerHTML += keyFrames; } //时针的动画规则名称和初始旋转度数作为参数传入 newKeyFrames("hour",hourDeg); //分针的动画规则名称和初始旋转度数作为参数传入 newKeyFrames("minute",minuteDeg); //秒针的动画规则名称和初始旋转度数作为参数传入 newKeyFrames("second",secondDeg); //把全部增加动画规则后的style样式标签追加到svg元素中 document.getElementsByTagName("svg")[0].appendChild(style); 复制代码
CSS部分,需要分别增加动画属性的类的定义。
/*秒针每旋转360度,需要60秒*/ .second{animation:second linear 60s infinite;} /*分针每旋转360度,需要3600秒*/ .minute{animation:minute linear 3600s infinite;} /*时针每旋转360度,需要216000秒*/ .hour{animation:hour linear 216000s infinite;} 复制代码
DOM结构中记得把类样式附加上。
<line class="pointer second" id="second" /> <line class="pointer minute" id="minute" /> <line class="pointer hour" id="hour" /> 复制代码
可以看一下最终的效果了
似乎还有哪里有点问题,秒针的跳帧效果!
/*把线性linear去掉,改成steps(60) 即一个动画周期60秒跳帧为60*/ .second{animation:second steps(60) 60s infinite;} 复制代码
无懈可击!codepen附上源码 base template of SVG+javascript+CSS3 clock
显而易见的是,第二种方法看上去并没有第一种那么简单,甚至可以说比较绕,那么为什么这里用了很多篇幅来探索这种方法的可行性?是因为这次的案例刚好是个时钟,适合用定时器而已,而大多数情况下,我们需要一种可接受变量作为动画规则参数的方法来解决问题,so。
5.以上是骨骼,以下才是灵魂
最难的部分已经完成,既然动画效果出来了,那么在此模板的基础上,可以做一些绚烂的效果了。(友情提示,建议在下面这些动效源码的基础上进行修改,有详细注释,可以直接用图层元素去替换)至于在哪个模板的基础上修改?全凭个人喜好,因为这个定时器是单线程的,不会吃内存,所以在这个案例中,暂时在这个模板的基础上替换。
<!DOCTYPE html> <!--重点注意:!!!!Ai导出之前一定要把指针都放置初始零点的位置--> <html lang="en"> <svg> <style type="text/css"> /* Ai导出时生成的样式 每次使用时需要替换*/ .st0{ } …… /* 旋转原点的值根据不同的底图需要重新定义 */ .pointer{transform-origin: } </style> <!--在进行图层 排序 时,遵循底图-时针-分针-秒针-覆盖层(如果有的话)的规律--> <g id="base"> 底图对应的路径 </g> <g class="pointer" id="hour"> 时针对应的路径 </g> <g class="pointer" id="minute"> 分针对应的路径 </g> <g class="pointer" id="second"> 秒针对应的路径 </g> <g id="overlay"> 覆盖层对应的路径 </g> </svg> <script> // 因为没有用jQuery,因此封装了一个最基本的函数 function $(id){ var idValue=document.getElementById(id); return idValue; } </script> <script> //定义获取当前时间转换成旋转变形角度的函数 function timeId(){ var dt=new Date(); //时针度数修正,增加分针对应的度数 var hourDeg=dt.getHours()*30 + dt.getMinutes()*0.5; //分针度数修正,增加秒针对应的度数 var minuteDeg=dt.getMinutes()*6+dt.getSeconds()*0.1; var secondDeg=dt.getSeconds()*6; //给时针追加旋转变形类样式 $("hour").style.cssText="transform:rotate("+hourDeg+"deg);"; //给分针追加旋转变形类样式 $("minute").style.cssText="transform:rotate("+minuteDeg+"deg);"; //给秒针追加旋转变形类样式 $("second").style.cssText="transform:rotate("+secondDeg+"deg);"; } // 定时器触发前先执行一次函数 timeId(); // 设置每1000ms触发一次的定时器 setInterval(timeId, 1000); </script> </html> 复制代码
喜欢clock?ok!比如这种不带刻度的简易风codepen链接
以下均为各种无聊的炫技系列,懒得看可直接略过,无妨无妨。
光秃秃的底盘太单调?来个简易刻度怎样?codepen链接
不怕麻烦的全数字刻度codepen链接
喜欢手表,说换就换,不就是替换一下的事情嘛codepen链接
太老土?那看看这种iWatch风格是不是你的菜
好了,不玩儿了,万变不离其宗。快过年了,最后来个中洋结合的,招财猫配金玉满堂金灿灿大福字的时钟。(我知道是猪年,但是招财猪,那个猪蹄子挥起来太有喜感,so)
关于招财猫的猫爪前后摆动可以参考我以前的一篇专栏, 《无立体,不动画,CSS3 3D 动画属性入门》 很基础的3D属性而已。只是因为是平面的,所以那个手臂的摆动会有些怪怪的。
祝各位新年鸿运当头,即使互联网寒冬再冷,也要笑着走下去。就酱。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Stylin' with CSS
Wyke-Smith, Charles / 2012-10 / $ 50.84
In this completely revised edition of his bestselling Stylin' with CSS, veteran designer and programmer Charles Wyke-Smith guides you through a comprehensive overview of designing Web pages with CSS, ......一起来看看 《Stylin' with CSS》 这本书的介绍吧!