JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

栏目: CSS · 发布时间: 5年前

内容简介: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>
复制代码

自然,这个最终的样子不是那么美,现在所有的指针都指向一个初始位置,即零时。

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

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类样式中。

为了测试是否好用,我让系统的时间暂时在窗口显示。

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

当调用这个函数时,可以看到当前时间与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);
复制代码
JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

这样的话,就得到了一枚丑丑的,但是可以与当前时间同步的时钟。 但是,这里有个小问题, 因为返回的系统时间是整数值,对于秒针而言,一格格的跳着走没什么问题,但对于分针尤其是时针而言,到了整点再跳一格,显然是与现实世界中的时钟不符的。 比如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;
复制代码

按接近整点截了一段动图,看一下效果

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟
实现了平滑过渡。这种方法的实现,其实并没有用到CSS3的动画属性,只用到了旋转变形属性。codepen附上全部源码 base template of SVG+javascript clock

4.扔掉定时器,使用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)

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

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" />
复制代码

可以看一下最终的效果了

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

似乎还有哪里有点问题,秒针的跳帧效果!

/*把线性linear去掉,改成steps(60) 即一个动画周期60秒跳帧为60*/
.second{animation:second steps(60) 60s  infinite;}
复制代码
JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

无懈可击!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链接

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

以下均为各种无聊的炫技系列,懒得看可直接略过,无妨无妨。

光秃秃的底盘太单调?来个简易刻度怎样?codepen链接

不怕麻烦的全数字刻度codepen链接

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

喜欢手表,说换就换,不就是替换一下的事情嘛codepen链接

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

太老土?那看看这种iWatch风格是不是你的菜

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

好了,不玩儿了,万变不离其宗。快过年了,最后来个中洋结合的,招财猫配金玉满堂金灿灿大福字的时钟。(我知道是猪年,但是招财猪,那个猪蹄子挥起来太有喜感,so)

关于招财猫的猫爪前后摆动可以参考我以前的一篇专栏, 《无立体,不动画,CSS3 3D 动画属性入门》 很基础的3D属性而已。只是因为是平面的,所以那个手臂的摆动会有些怪怪的。

JavaScript牛刀小试,结合CSS3动画属性来做一个系统时间同步的时钟

祝各位新年鸿运当头,即使互联网寒冬再冷,也要笑着走下去。就酱。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Stylin' with CSS

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》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具