css3clock.js - 一个用CSS3与纯js实现的简单时钟
前言
项目代码明细可以查看我Github上的源码:https://github.com/nelsonkuang/css3clock.js
快速浏览更多在线 Demo
想查看源代码,可以自行F12,或在github中直接查看源码,或者欢迎直接留言。
实现思路
主要是用CSS3控制时针、分针和秒针旋转;时针每12小时转360度,分针每小时转360度,还有秒针每分钟转360度;但初始状态的各条针的位置和角度就要用js来控制,用js去获取浏览器加载进来的css rule,然后根据时钟的初始时间分别计算出时针、分针和秒针的初始角度去调整css rule来初始化时钟。
实现过程
1、静态实现;先用html+css把时钟的位置固定起来,做出时钟的样子
- html代码如下:
<div id="clockBeijing">
<div class="clock">
<div class="outerCircle"></div>
<div class="innerCircle"></div>
<div class="numbers">
<div class="num num1">1</div>
<div class="num num2">2</div>
<div class="num num3">3</div>
<div class="num num4">4</div>
<div class="num num5">5</div>
<div class="num num6">6</div>
<div class="num num7">7</div>
<div class="num num8">8</div>
<div class="num num9">9</div>
<div class="num num10">10</div>
<div class="num num11">11</div>
<div class="num num12">12</div>
</div>
<div class="hands">
<div class="hand hourHand"></div>
<div class="hand minuteHand"></div>
<div class="hand secondHand"></div>
<div class="hand circle"></div>
</div>
</div>
</div>
- css代码如下:
html, body {
margin: 0;
padding: 0;
font-family: Arial;
-webkit-text-size-adjust:none;
}
#clockBeijing{
width: 33.33%;
float: left;
padding: 20px 0;
border-radius: 30px;
-webkit-border-radius: 30px;
-moz-border-radius: 30px;
}
#clockBeijing {
background-color:#68ff7c;
}
.clock
{
width: 200px;
height: 200px;
position: relative;
margin: auto;
}
.clock .outerCircle {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 3px solid black;
border-radius: 50%;
-webkit-border-radius: 50%;
}
.clock .innerCircle {
position: absolute;
top: 18%;
left: 18%;
width: 64%;
height: 64%;
border: 1px solid black;
border-radius: 50%;
-webkit-border-radius: 50%;
}
.clock .numbers {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.clock .numbers .num {
font-family: Arial;
font-size: 20px;
font-weight: bold;
color: grey;
position: absolute;
text-align: center;
width: 25px;
height: 25px;
}
.clock .numbers .num1 {
top: 12%;
right: 22%;
}
.clock .numbers .num2 {
top: 25%;
right: 8%;
}
.clock .numbers .num3 {
top: 45%;
right: 3%;
}
.clock .numbers .num4 {
bottom: 25%;
right: 8%;
}
.clock .numbers .num5 {
bottom: 7%;
right: 22%;
}
.clock .numbers .num6 {
bottom: 0;
left: 45%;
}
.clock .numbers .num7 {
bottom: 7%;
left: 22%;
}
.clock .numbers .num8 {
bottom: 25%;
left: 8%;
}
.clock .numbers .num9 {
top: 45%;
left: 3%;
}
.clock .numbers .num10 {
top: 25%;
left: 8%;
}
.clock .numbers .num11 {
top: 12%;
left: 22%;
}
.clock .numbers .num12 {
top: 5%;
left: 45%;
}
.clock .hands {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
margin: 3px;
}
.clock .hand {
position: absolute;
}
.clock .hands .hourHand {
width: 30%;
height: 6%;
background-color: black;
border-radius: 3px;
-webkit-border-radius: 3px;
left: 50%;
top: 47%;
}
.clock .hands .minuteHand {
width: 46%;
height: 4%;
background-color: black;
border-radius: 3px;
-webkit-border-radius: 3px;
left: 50%;
top: 48%;
}
.clock .hands .secondHand {
width: 64%;
height: 2%;
background-color: black;
border-radius: 3px;
-webkit-border-radius: 3px;
left: 34%;
top: 49%;
}
.clock .hands .circle {
width: 8%;
height: 8%;
background-color: silver;
border-radius: 50%;
-webkit-border-radius: 50%;
left: 46%;
top: 46%;
}
2、加上CSS3动画,css3代码如下:
/************* Clock Beijing ****************/
/*
@creator: Nelson Kuang
@name: rotateSecondBeijing - second hand of the clock
@usage: <div class="rotateSecondBeijing">Example</div>
*/
@-webkit-keyframes rotateSecondBeijing {
from {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotateSecondBeijing {
from {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-moz-keyframes rotateSecondBeijing {
from {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: 24.2% center;
-moz-transform-origin: 24.2% center;
transform-origin: 24.2% center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotateSecondBeijing {
-moz-animation-name: rotateSecondBeijing;
-webkit-animation-name: rotateSecondBeijing;
animation-name: rotateSecondBeijing;
-moz-animation-timing-function: linear;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-moz-animation-fill-mode: both;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-moz-animation-duration: 60s;
-webkit-animation-duration: 60s;
animation-duration: 60s;
-moz-animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
/*
@creator: Nelson Kuang
@name: rotateMinuteBeijing - minute hand of the clock
@usage: <div class="rotateMinuteBeijing">Example</div>
*/
@-webkit-keyframes rotateMinuteBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotateMinuteBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-moz-keyframes rotateMinuteBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotateMinuteBeijing {
-webkit-animation-name: rotateMinuteBeijing;
-moz-animation-name: rotateMinuteBeijing;
animation-name: rotateMinuteBeijing;
-moz-animation-timing-function: linear;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-moz-animation-fill-mode: both;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-moz-animation-duration: 3600s;
-webkit-animation-duration: 3600s;
animation-duration: 3600s;
-moz-animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
/*
@creator: Nelson Kuang
@name: rotateHourBeijing - hour hand of the clock
@usage: <div class="rotateHourBeijing">Example</div>
*/
@-webkit-keyframes rotateHourBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@keyframes rotateHourBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
@-moz-keyframes rotateHourBeijing {
from {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
transform: rotate(0deg);
}
to {
-webkit-transform-origin: left center;
-moz-transform-origin: left center;
transform-origin: left center;
-webkit-transform: rotate(360deg);
-moz-transform: rotate(360deg);
transform: rotate(360deg);
}
}
.rotateHourBeijing {
-webkit-animation-name: rotateHourBeijing;
-moz-animation-name: rotateHourBeijing;
animation-name: rotateHourBeijing;
-moz-animation-timing-function: linear;
-webkit-animation-timing-function: linear;
animation-timing-function: linear;
-moz-animation-fill-mode: both;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
-moz-animation-duration: 43200s;
-webkit-animation-duration: 43200s;
animation-duration: 43200s;
-moz-animation-iteration-count: infinite;
-webkit-animation-iteration-count: infinite;
animation-iteration-count: infinite;
}
3、javascript代码如下
1) js程序入口
css3clock.ready(function () {
css3clock.init(document.getElementById("clockTokyo"), css3clock.worldDates.TokyoDate(), {
secondHandAnimateClass: "rotateSecondTokyo",
minuteHandAnimateClass: "rotateMinuteTokyo",
hourHandAnimateClass: "rotateHourTokyo"
});
css3clock.init(document.getElementById("clockBeijing"), css3clock.worldDates.BeiJingDate(), {
secondHandAnimateClass: "rotateSecondBeijing",
minuteHandAnimateClass: "rotateMinuteBeijing",
hourHandAnimateClass: "rotateHourBeijing"
});
css3clock.init(document.getElementById("clockNewYork"), css3clock.worldDates.NewYorkDate(), {
secondHandAnimateClass: "rotateSecondNewyork",
minuteHandAnimateClass: "rotateMinuteNewyork",
hourHandAnimateClass: "rotateHourNewyork"
});
css3clock.init(document.getElementById("clockMoscow"), css3clock.worldDates.MoscowDate(), {
secondHandAnimateClass: "rotateSecondMoscow",
minuteHandAnimateClass: "rotateMinuteMoscow",
hourHandAnimateClass: "rotateHourMoscow"
});
css3clock.init(document.getElementById("clockLondon"), css3clock.worldDates.LondonDate(), {
secondHandAnimateClass: "rotateSecondLondon",
minuteHandAnimateClass: "rotateMinuteLondon",
hourHandAnimateClass: "rotateHourLondon"
});
css3clock.init(document.getElementById("clockParis"), css3clock.worldDates.ParisDate(), {
secondHandAnimateClass: "rotateSecondParis",
minuteHandAnimateClass: "rotateMinuteParis",
hourHandAnimateClass: "rotateHourParis"
});
css3clock.init(document.getElementById("clockSydney"), css3clock.worldDates.SydneyDate(), {
secondHandAnimateClass: "rotateSecondSydney",
minuteHandAnimateClass: "rotateMinuteSydney",
hourHandAnimateClass: "rotateHourSydney"
});
css3clock.init(document.getElementById("clockVancouver"), css3clock.worldDates.VancouverDate(), {
secondHandAnimateClass: "rotateSecondVancouver",
minuteHandAnimateClass: "rotateMinuteVancouver",
hourHandAnimateClass: "rotateHourVancouver"
});
});
2) js时钟类
// AMD with global, Node, or global
; (function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['css3Clock'], function (css3Clock) {
// Also create a global in case some scripts
// that are loaded still are looking for
// a global even when an AMD loader is in use.
return (root.css3Clock = factory(css3Clock));
});
} else {
// Browser globals (root is window)
root.css3Clock = factory(root.css3Clock);
}
}(this, function (css3Clock) {
// Baseline
/* -------------------------------------------------------------------------- */
var root = this || global;
var previouscss3Clock = root.css3Clock;
css3Clock = {};
css3Clock.VERSION = "0.1.0";
//the second hand, minute hand and hour hand of the clock
var hands = function (date, animateCss) {
var h = {},
d = date || new Date();
h.hour = d.getHours() >= 12 ? d.getHours() - 12 : d.getHours();
h.minute = d.getMinutes();
h.second = d.getSeconds();
h.hourHandRotate = (h.hour + h.minute / 60 + h.second / 3600) * 30 - 90;
h.minuteHandRotate = (h.minute + h.second / 60) * 6 - 90;
h.secondHandRotate = (h.second) * 6 - 90;
h.secondHandAnimateClass = animateCss ? animateCss.secondHandAnimateClass || "rotateSecond" : "rotateSecond";
h.minuteHandAnimateClass = animateCss ? animateCss.minuteHandAnimateClass || "rotateMinute" : "rotateMinute";
h.hourHandAnimateClass = animateCss ? animateCss.hourHandAnimateClass || "rotateHour" : "rotateHour";
return h;
};
//update the css animation keyframes for clock hands initialization
//var updateRotateRule = function (cssRules, handRotate) {
function updateRotateRule(cssRules, handRotate) {
var from = cssRules.findRule("from").cssText.replace("(0deg)", "(" + handRotate + "deg)").replace("(0deg)", "(" + handRotate + "deg)").replace("(0deg)", "(" + handRotate + "deg)"),
to = cssRules.findRule("to").cssText.replace("360", handRotate + 360).replace("360", handRotate + 360).replace("360", handRotate + 360);
cssRules.deleteRule("from");
cssRules.deleteRule("to");
if (cssRules.insertRule) {
cssRules.insertRule(from);
cssRules.insertRule(to);
} else if (cssRules.appendRule) {//Firefox supported
cssRules.appendRule(from);
cssRules.appendRule(to);
}
};
//the dates all over the world
var worldDates = css3Clock.worldDates = {
UTC: function () {
var date = new Date();
date.setTime(date.getTime() + date.getTimezoneOffset() * 60000);
return date;
},
BeiJingDate: function () {
var date = new Date(),
offset = 8,
utc = worldDates.UTC();
date.setTime(utc.getTime() + (3600000 * offset));
return date;
},
NewYorkDate: function () {
var utc = worldDates.UTC(),
offset = -5,
date = new Date(),
summerDateStart = new Date(date.getFullYear(), 3, 8, 2, 0, 0, 0),
summerDateEnd = new Date(date.getFullYear(), 11, 1, 2, 0, 0, 0),
nonSummerTime = utc.getTime() + (3600000 * offset);
date.setTime((nonSummerTime >= summerDateStart.getTime() && nonSummerTime <= summerDateEnd.getTime()) ? (nonSummerTime + 3600000) : nonSummerTime);
return date;
},
VancouverDate: function () {
var utc = worldDates.UTC(),
offset = -8,
date = new Date(),
summerDateStart = new Date(date.getFullYear(), 3, 8, 2, 0, 0, 0),
summerDateEnd = new Date(date.getFullYear(), 11, 1, 2, 0, 0, 0),
nonSummerTime = utc.getTime() + (3600000 * offset);
date.setTime((nonSummerTime >= summerDateStart.getTime() && nonSummerTime <= summerDateEnd.getTime()) ? (nonSummerTime + 3600000) : nonSummerTime);
return date;
},
TokyoDate: function () {
var date = new Date(),
offset = 9,
utc = worldDates.UTC();
date.setTime(utc.getTime() + (3600000 * offset));
return date;
},
MoscowDate: function () {
var date = new Date(),
offset = 3,
utc = worldDates.UTC();
date.setTime(utc.getTime() + (3600000 * offset));
return date;
},
LondonDate: function () {
var utc = worldDates.UTC(),
offset = 0,
date = new Date(),
summerDateStart = new Date(date.getFullYear(), 3, 29, 1, 0, 0, 0),
summerDateEnd = new Date(date.getFullYear(), 10, 25, 2, 0, 0, 0),
nonSummerTime = utc.getTime() + (3600000 * offset);
date.setTime((nonSummerTime >= summerDateStart.getTime() && nonSummerTime <= summerDateEnd.getTime()) ? (nonSummerTime + 3600000) : nonSummerTime);
return date;
},
ParisDate: function () {
var utc = worldDates.UTC(),
offset = 1,
date = new Date(),
summerDateStart = new Date(date.getFullYear(), 3, 29, 1, 0, 0, 0),
summerDateEnd = new Date(date.getFullYear(), 10, 25, 2, 0, 0, 0),
nonSummerTime = utc.getTime() + (3600000 * offset);
date.setTime((nonSummerTime >= summerDateStart.getTime() && nonSummerTime <= summerDateEnd.getTime()) ? (nonSummerTime + 3600000) : nonSummerTime);
return date;
},
SydneyDate: function () {
var date = new Date(),
offset = 10,
utc = worldDates.UTC();
date.setTime(utc.getTime() + (3600000 * offset));
return date;
}
};
//start the clock
css3Clock.start = function (el,date,hands) {
var s = getElementsByClassName(el, "secondHand")[0],
m = getElementsByClassName(el, "minuteHand")[0],
h = getElementsByClassName(el, "hourHand")[0],
daysEn = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
daysCn = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
dayTimeEn = ["AM","PM"],
dayTimeCn=["零晨","早上","中午","下午","晚上"],
getDayTimeCn = function () {
var d = date.getHours();
if (d >= 0 && d < 5) {
return dayTimeCn[0];
} else if (d >= 5 && d < 11) {
return dayTimeCn[1];
} else if (d >= 11 && d < 13) {
return dayTimeCn[2];
} else if (d >= 13 && d < 18) {
return dayTimeCn[3];
} else if (d >= 18 && d <= 23) {
return dayTimeCn[4];
}
};
/*removeClass(s, hands.secondHandAnimateClass);
removeClass(m, hands.minuteHandAnimateClass);
removeClass(h, hands.hourHandAnimateClass);*/
addClass(s, hands.secondHandAnimateClass);
addClass(m, hands.minuteHandAnimateClass);
addClass(h, hands.hourHandAnimateClass);
var elEn = getElementsByClassName(el, "dateEN")[0],
elCn = getElementsByClassName(el, "dateCN")[0];
elEn.innerText = elEn.textContent = date.getFullYear().toString() + "/"
+ (date.getMonth() + 1).toString() + "/"
+ date.getDate().toString() + " "
+ (date.getHours() >= 12 ? dayTimeEn[1] : dayTimeEn[0]) + " "
+ daysEn[date.getDay()];
elCn.innerText = elCn.textContent = date.getFullYear().toString() + "年"
+ (date.getMonth() + 1).toString() + "月"
+ date.getDate().toString() + "日"
+ getDayTimeCn() + " "
+ daysCn[date.getDay()];
}
//clock initialization
css3Clock.init = function (el, date, animateCss) {
var ss = document.styleSheets,
h = hands(date, animateCss);
for (var i = ss.length - 1; i >= 0; i--) {
try {
var s = ss[i],
rs = s.cssRules ? s.cssRules :
s.rules ? s.rules :
[];
for (var j = rs.length - 1; j >= 0; j--) {
if ((rs[j].type === window.CSSRule.WEBKIT_KEYFRAMES_RULE || rs[j].type === window.CSSRule.MOZ_KEYFRAMES_RULE)) {
switch (rs[j].name) {
case h.secondHandAnimateClass:
updateRotateRule(rs[j], h.secondHandRotate);
break;
case h.minuteHandAnimateClass:
updateRotateRule(rs[j], h.minuteHandRotate);
break;
case h.hourHandAnimateClass:
updateRotateRule(rs[j], h.hourHandRotate);
break;
}
}
}
}
catch (e) { }
}
css3Clock.start(el,date, h);
}
//like jQuery $(document)ready(fn)
css3Clock.ready = function (fn) {
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", function () {
document.removeEventListener("DOMContentLoaded", arguments.callee, false);
fn();
}, false);
} else if (document.attachEvent) {
document.attachEvent("onreadystatechange", function () {
if (document.readyState === "complete") {
document.detachEvent("onreadystatechange", arguments.callee);
fn();
}
});
}
};
/***Utility*******/
function hasClass(obj, cls) {
return obj.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'));
}
function addClass(obj, cls) {
if (!hasClass(obj, cls)) obj.className += " " + cls;
}
function removeClass(obj, cls) {
if (hasClass(obj, cls)) {
var reg = new RegExp('(\\s|^)' + cls + '(\\s|$)');
obj.className = obj.className.replace(reg, ' ');
}
}
function getElementsByClassName(obj, cls) {
if (obj.getElementsByClassName) {
return obj.getElementsByClassName(cls);
}
else {
var objs = obj.getElementsByTagName("*"),
resultsArr = [];
for (var o in objs) {
if (hasClass(objs[o], cls)) {
resultsArr.push(objs[o]);
}
}
return resultsArr;
}
}
/********************/
return css3Clock;
}))