Javascript 实现[网红] 时间轮盘

话不多说,先上图。

成品链接

Javascript 实现[网红] 时间轮盘

Javascript 实现[网红] 时间轮盘

Javascript 实现[网红] 时间轮盘

大致效果如上图,接下来就开始制作吧。

HTML部分:

我们需要将容器旋转rotate使之以圆点为中心。

怎么转呢,请看图。

Javascript 实现[网红] 时间轮盘

将同一级的容器用一个大的容器包裹起来,绝对定位。这时,所有的子容器会重合在一起。

然后我们用360°去除以子容器个数,可以得到每个子容器的角度差,采用角度差来旋转每个容器。

效果如图:

Javascript 实现[网红] 时间轮盘

我们可以看到,他是重合在一起的,应位默认的旋转中心是容器的中心,

这时我们需要改变旋转中心点,

添加css属性 transform-origin: -50% 50%;

效果如图:

Javascript 实现[网红] 时间轮盘

我们可以发现此时旋转过后的图形超出了父容器,所以需要改变他的位置,根据旋转可知。

图形总长度为子容器长度的3倍(中间空白处为一个子容器长度)

高度为 空白处高度加上 子容器高度的两倍

经过位置变换(再填上文字)

效果如图:

Javascript 实现[网红] 时间轮盘

以上讲解代码如下:

<!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>时间轮盘 一</title>
<style>
#wrapper {
width: 500px;
height: 500px;
margin: 100px auto;
background: #ccc;
}
.container {
width: 100%;
height: 100%;
position: relative;
left: 300px;
top: 210px;
}
.box {
width: 150px;
height: 30px;
background: orange;
/* border: 1px solid black; */
position: absolute;
top: 0;
left: 0;
transform-origin: -50% 50%;
}
</style>
</head>
<body>
<div id="wrapper">
<div class="container">
<div class="box">我是1</div>
<div class="box" style="transform: rotate(45deg)">我是2</div>
<div class="box" style="transform: rotate(90deg)">我是3</div>
<div class="box" style="transform: rotate(135deg)">我是4</div>
<div class="box" style="transform: rotate(180deg)">我是5</div>
<div class="box" style="transform: rotate(225deg)">我是6</div>
<div class="box" style="transform: rotate(270deg)">我是7</div>
<div class="box" style="transform: rotate(315deg)">我是</div>
</div>
</div>
</body>
</html>

基本布局就是这样,接下来我们需要多制作几个,分别存放星期、时分秒。

成品HTML代码部分如下:

<!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">
<link rel="stylesheet" href="css/TimeRoulette.css">
<title>时间轮盘</title>
</head>
<body>
<div class="wrapper">
<h1 class="workTitle">时间轮盘</h1>
<p class="one-text">天可补,海可填,南山可移,日月既往,不可复追。</p>
<div class="timeBox">
<div class="year-wrapper" title="点击更换背景图片">
<p></p>
</div>
<div class="week-wrapper">
<ul class="week-content"> </ul>
</div>
<div class="hours-wrapper">
<ul class="hours-content"> </ul>
</div>
<div class="minutes-wrapper">
<ul class="minutes-content"> </ul>
</div>
<div class="seconds-wrapper">
<ul class="seconds-content"> </ul>
</div>
</div>
</div>
</body>
<script src="js/jquery.js"></script>
<script src="js/TimeRoulette.js"></script>
</html>

大家可以发现,我们的hrml中并没有数据,有关星期,时分秒,的数据我们通过js生成,毕竟太多了,而且有规律可循。

这里我们使用了jquery来实现dom操作

接下来就是JS部分了!

首先我们需要几个函数,将数字转换成大写(仅做了1000以内),将年份转化为干纪年法(显得霸气),将24小时转化为时辰(实现一半,所以此处未加上)

// 数字大小写转换
function numberToZh(num) {
var zh = ["零","壹","贰","叁","肆","伍","陆","柒","捌","玖","拾","佰","仟","万"];
var res = "";
if(num <= 10) {
res = zh[num];
} else if(num < 20) {
var bits = num % 10;
res = zh[10] + zh[bits];
} else if(num < 100) {
var bits = num % 10;
var decade = parseInt(num / 10);
if(bits == 0) {
res = zh[decade] + zh[10] + "整";
} else {
res = zh[decade] + zh[10] + zh[bits];
} }
return res;
} // 干支纪年法
function toAncientYear(year) {
var sky = ["", "辛", "壬", "癸", "甲", "乙", "丙", "丁", "戊", "己", "庚"];
var land = ["", "酉", "戌", "亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申"]; // 用年份除以10得数中余数相对应的便是天干
var one = year % 10;
// 用年份除以12得数中余数相对应的便是地支
var two = year % 12; var res = sky[one] + land[two];
return res;
} //时间转时辰
function toAncientHours(num) {
var res = "";
switch(num) {
case 1 : res = "子";break;
case 2 : res = "丑";break;
case 3 : res = "寅";break;
case 4 : res = "卯";break;
case 5 : res = "辰";break;
case 6 : res = "巳";break;
case 7 : res = "午";break;
case 8 : res = "未";break;
case 9 : res = "申";break;
case 10 : res = "酉";break;
case 11 : res = "戌";break;
case 12 : res = "亥";break;
}
return res;
}

有了这几个小函数,我们就可以初始化时间轮盘了

代码:

function init() {

// 更换背景图片
$(".timeBox .year-wrapper").click(function(){
$("body").css("background-image", "url(images/background"+ Math.ceil(Math.random()*4) +".jpg)")
})
// 设置文本值
setNumText(); // 设置干支纪年时间
var nowYear = (new Date).getFullYear();
var acientYear = toAncientYear(nowYear);
$(".year-wrapper p").text(acientYear).attr("title","公元" + nowYear + "农历" + acientYear +"年"); // 初始化内容位置,旋转到指定角度
var weekLen = $(".week-content li").length;
var weekDeg = 360/weekLen;
$(".week-content li").each(function(index) {
$(this).css({
"transform":"rotate("+index*weekDeg+"deg)",
"transform-origin":"-100% 50%",
"margin-left":parseInt($(this).css("width")) * 3 + "px",
"margin-top":parseInt($(this).css("width")) * 2 - 10 + "px"
})
}) // 时
var hoursLen = $(".hours-content li").length;
var hoursDeg = 360/hoursLen;
$(".hours-content li").each(function(index) {
$(this).css({
"transform":"rotate("+index*hoursDeg+"deg)",
"transform-origin":"-250% 50%",
"margin-left":parseInt($(this).css("width")) * 6 + "px",
"margin-top":parseInt($(this).css("width")) * 3.5 - 10 + "px"
})
}) //分
var minutesLen = $(".minutes-content li").length;
var minutesDeg = 360/minutesLen;
$(".minutes-content li").each(function(index) {
$(this).css({
"transform":"rotate("+index*minutesDeg+"deg)",
"transform-origin":"-400% 50%",
"margin-left":parseInt($(this).css("width")) * 9 + "px",
"margin-top":parseInt($(this).css("width")) * 5 - 10 + "px"
})
}) //秒
var secondsLen = $(".seconds-content li").length;
var secondsDeg = 360/secondsLen;
$(".seconds-content li").each(function(index) {
$(this).css({
"transform":"rotate("+index*secondsDeg+"deg)",
"transform-origin":"-550% 50%",
"margin-left":parseInt($(this).css("width")) * 12 + "px",
"margin-top":parseInt($(this).css("width")) * 6.5 - 10 + "px"
})
}) //每秒刷新一次
run();
}
// 设置文本内容
function setNumText(){
for(var i = 7; i > 0; i --) {
$(".week-content").append("<li data-time = "+ i +"> 星期"+ numberToZh(i) +"<li>")
}
for(var i = 12;i > 0; i --) {
$(".hours-content").append("<li data-time = "+ i +">"+ numberToZh(i) +"时<li>")
}
for(var i = 60;i > 0; i --) {
$(".minutes-content").append("<li data-time = "+ i +">"+ numberToZh(i) +"<li>")
}
for(var i = 60;i > 0; i --) {
$(".seconds-content").append("<li data-time = "+ i +">"+ numberToZh(i) +"<li>")
}
}

此时,项目的静态效果已经有了,我们需要让他动起来,也就是上面代码中的run()函数

// 刷新轮盘
function run() {
clearInterval(timer);
var date = new Date();//获取本地时间
// 分别获取时分秒年
var week = date.getDay();
var hours = date.getHours() % 12;
var minutes = date.getMinutes();
var seconds = date.getSeconds(); // 计算对应的旋转角度差
// rotateIndexH 为定义的全局变量,存储了小时的旋转圈数
// rotateIndexM、rotateIndexS 同理为分、秒的
// week
var weekRote = 360 / 7 * (week); // hours
var hoursRote = 360 / 12 * (hours) + rotateIndexH * 360; // minites secondes
var tempDeg = 360 / 60;
var minutesRote = tempDeg * (minutes) + rotateIndexM * 360;
var secondsRote = tempDeg * (seconds) + rotateIndexS * 360;
//var secondsRote = tempDeg * (seconds + 1) + rotateIndexS*360; // 加一是为了滚到位置再变色,去掉会先变色再滚到位置 // 旋转 秒 的位置
$(".seconds-wrapper").css("transform", "rotate(" + secondsRote + "deg)"); // 点亮 由于时间是从0开始计数的所以这里判断
var secondDot = seconds == 0 ? 60 : seconds;
var minuteDot = minutes == 0 ? 60 : minutes;
var hourDot = hours == 0 ? 60 : hours;
var weekDot = hours == 0 ? 7 : week;
// $(".hour-content li[data-time="+hourDot+"]").addClass("active").next("li").removeClass("active");
// $(".minutes-content li[data-time="+minuteDot+"]").addClass("active").prev("li").removeClass("active");
//$(".seconds-content li[data-time='"+secondDot+"']").addClass("active").next("li").removeClass("active"); //为了节省性能,每当秒满60时,才去指向时、分的
if (seconds == 59 || rotateIndexH == 0) {
$(".week-wrapper").css("transform", "rotate(" + weekRote + "deg)");
$(".hours-wrapper").css("transform", "rotate(" + hoursRote + "deg)");
$(".minutes-wrapper").css("transform", "rotate(" + minutesRote + "deg)"); //给当前时间的节点添加active 类 (这里 练一下选择器所以写成了一句。)
$(".week-content li[data-time=" + weekDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
$(".hours-content li[data-time=" + hourDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
$(".minutes-content li[data-time=" + minuteDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
} // 秒时每秒都需要更新的
$(".seconds-content li[data-time=" + secondDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active"); // 旋转圈数加一(解决360°转到0°时的bug)
hours === 11 ? rotateIndexH++ : 0;
minutes === 59 ? rotateIndexM++ : 0;
seconds === 59 ? rotateIndexS++ : 0; // 让函数一秒钟执行一次
var timer = setTimeout(run, 1000);
}

具体都做了详细的注释,这里就不多提,有个小问题,

$(".seconds-content li[data-time='"+secondDot+"']").addClass("active").next("li").removeClass("active");
不能获取,有人知道原因吗。。。。
欢迎告知。 CSS部分就不多说了,看代码:
*{
padding:;
margin:;
color: #eee;
user-select: none;
}
body {
background: #bebebe;
background-image: url(../images/background2.jpg);
background-repeat: no-repeat;
background-position:top;
background-attachment:fixed;
}
ul {
list-style: none;
}
li {
position: absolute;
display: inline-block;
}
.wrapper {
overflow: hidden;
height: 100vh;
box-sizing: border-box;
padding-top: 50px;
}
.timeBox {
margin: 5px auto;
width: 800px;
height: 800px;
/* background: #ccc; */
position: relative;
}
.wrapper .workTitle {
color: #878787;
font-family: Arial, Helvetica, sans-serif;
text-align: center;
line-height: 2em;
letter-spacing: .3em;
}
.wrapper .one-text {
color: #dbdbdb;
text-align: center;
font-size: 18px;
font-style: italic;
text-shadow: 8px 7px 4px rgba(100,150,200,0.8);
letter-spacing: .2em;
}
.timeBox .week-wrapper {
transition: 1s;
position: absolute;
width: 200px;
height: 200px;
top: 300px;
left: 300px;
z-index:;
}
.timeBox .week-wrapper .week-content li {
width: 50px;
}
.timeBox .hours-wrapper {
transition: ease 1s;
position: absolute;
width: 350px;
height: 350px;
top: 225px;
left: 225px;
z-index:;
}
.timeBox .hours-wrapper .hours-content li {
width: 50px;
}
.timeBox .minutes-wrapper {
transition: 1s;
position: absolute;
width: 500px;
height: 500px;
top: 150px;
left: 150px;
z-index:;
}
.timeBox .minutes-wrapper .minutes-content li {
width: 50px;
}
.timeBox .seconds-wrapper {
transition: all 1s linear;
position: absolute;
width: 650px;
height: 650px;
top: 75px;
left: 75px;
z-index:;
}
.timeBox .seconds-wrapper .seconds-content li {
transition: .5s;
width: 50px;
}
.timeBox .year-wrapper {
width: 80px;
height: 80px;
border-radius: 50%;
position: absolute;
top:50%;
left: 50%;
transform: translate(-50%,-50%);
cursor: pointer;
z-index:;
}
.timeBox .year-wrapper p {
text-align: center;
line-height: 80px;
font-size: 18px;
font-weight: bold;
}
.timeBox .year-wrapper::after {
content:"";
display: block;
width: 300px;
height: 26px;
/* background:rgba(139,90,43); */
/* border:1px solid #aaa;
border-radius: 3px; */
position: absolute;
top:27px;
left: 80px;
}
.active {
/* color: rgb(139,90,43); */
color: #FF7F00;
}
@media screen and (max-width:700px) {
.wrapper .timeBox {
transform: scale(0.5,0.5) translate(-50%,-50%);
margin: 0 auto;
}
.wrapper .timeBox ul li {
font-size:16px;
}
}

最后,附上完整的代码;

var rotateIndexH = 0;
var rotateIndexM = 0;
var rotateIndexS = 0;
init(); function init() { // 更换背景图片
$(".timeBox .year-wrapper").click(function () {
$("body").css("background-image", "url(images/background" + Math.ceil(Math.random() * 4) + ".jpg)")
})
// 设置文本值
setNumText(); // 设置干支纪年时间
var nowYear = (new Date).getFullYear();
var acientYear = toAncientYear(nowYear);
$(".year-wrapper p").text(acientYear).attr("title", "公元" + nowYear + "农历" + acientYear + "年"); // 初始化内容位置,旋转到指定角度
var weekLen = $(".week-content li").length;
var weekDeg = 360 / weekLen;
$(".week-content li").each(function (index) {
$(this).css({
"transform": "rotate(" + index * weekDeg + "deg)",
"transform-origin": "-100% 50%",
"margin-left": parseInt($(this).css("width")) * 3 + "px",
"margin-top": parseInt($(this).css("width")) * 2 - 10 + "px"
})
}) // 时
var hoursLen = $(".hours-content li").length;
var hoursDeg = 360 / hoursLen;
$(".hours-content li").each(function (index) {
$(this).css({
"transform": "rotate(" + index * hoursDeg + "deg)",
"transform-origin": "-250% 50%",
"margin-left": parseInt($(this).css("width")) * 6 + "px",
"margin-top": parseInt($(this).css("width")) * 3.5 - 10 + "px"
})
}) //分
var minutesLen = $(".minutes-content li").length;
var minutesDeg = 360 / minutesLen;
$(".minutes-content li").each(function (index) {
$(this).css({
"transform": "rotate(" + index * minutesDeg + "deg)",
"transform-origin": "-400% 50%",
"margin-left": parseInt($(this).css("width")) * 9 + "px",
"margin-top": parseInt($(this).css("width")) * 5 - 10 + "px"
})
}) //秒
var secondsLen = $(".seconds-content li").length;
var secondsDeg = 360 / secondsLen;
$(".seconds-content li").each(function (index) {
$(this).css({
"transform": "rotate(" + index * secondsDeg + "deg)",
"transform-origin": "-550% 50%",
"margin-left": parseInt($(this).css("width")) * 12 + "px",
"margin-top": parseInt($(this).css("width")) * 6.5 - 10 + "px"
})
}) //每秒刷新一次
run();
} // 设置文本内容
function setNumText() {
for (var i = 7; i > 0; i--) {
$(".week-content").append("<li data-time = " + i + "> 星期" + numberToZh(i) + "<li>")
}
for (var i = 12; i > 0; i--) {
$(".hours-content").append("<li data-time = " + i + ">" + numberToZh(i) + "时<li>")
}
for (var i = 60; i > 0; i--) {
$(".minutes-content").append("<li data-time = " + i + ">" + numberToZh(i) + "<li>")
}
for (var i = 60; i > 0; i--) {
$(".seconds-content").append("<li data-time = " + i + ">" + numberToZh(i) + "<li>")
}
} // 数字大小写转换
function numberToZh(num) {
var zh = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖", "拾", "佰", "仟", "万"];
var res = "";
if (num <= 10) {
res = zh[num];
} else if (num < 20) {
var bits = num % 10;
res = zh[10] + zh[bits];
} else if (num < 100) {
var bits = num % 10;
var decade = parseInt(num / 10);
if (bits == 0) {
res = zh[decade] + zh[10] + "整";
} else {
res = zh[decade] + zh[10] + zh[bits];
} }
return res;
} // 刷新轮盘
function run() {
clearInterval(timer);
var date = new Date();//获取本地时间
// 分别获取时分秒年
var week = date.getDay();
var hours = date.getHours() % 12;
var minutes = date.getMinutes();
var seconds = date.getSeconds(); // 计算对应的旋转角度差
// rotateIndexH 为定义的全局变量,存储了小时的旋转圈数
// rotateIndexM、rotateIndexS 同理为分、秒的
// week
var weekRote = 360 / 7 * (week); // hours
var hoursRote = 360 / 12 * (hours) + rotateIndexH * 360; // minites secondes
var tempDeg = 360 / 60;
var minutesRote = tempDeg * (minutes) + rotateIndexM * 360;
var secondsRote = tempDeg * (seconds) + rotateIndexS * 360;
//var secondsRote = tempDeg * (seconds + 1) + rotateIndexS*360; // 加一是为了滚到位置再变色,去掉会先变色再滚到位置 // 旋转 秒 的位置
$(".seconds-wrapper").css("transform", "rotate(" + secondsRote + "deg)"); // 点亮 由于时间是从0开始计数的所以这里判断
var secondDot = seconds == 0 ? 60 : seconds;
var minuteDot = minutes == 0 ? 60 : minutes;
var hourDot = hours == 0 ? 60 : hours;
var weekDot = hours == 0 ? 7 : week;
// $(".hour-content li[data-time="+hourDot+"]").addClass("active").next("li").removeClass("active");
// $(".minutes-content li[data-time="+minuteDot+"]").addClass("active").prev("li").removeClass("active");
//$(".seconds-content li[data-time='"+secondDot+"']").addClass("active").next("li").removeClass("active"); //为了节省性能,每当秒满60时,才去指向时、分的
if (seconds == 59 || rotateIndexH == 0) {
$(".week-wrapper").css("transform", "rotate(" + weekRote + "deg)");
$(".hours-wrapper").css("transform", "rotate(" + hoursRote + "deg)");
$(".minutes-wrapper").css("transform", "rotate(" + minutesRote + "deg)"); //给当前时间的节点添加active 类 (这里 练一下选择器所以写成了一句。)
$(".week-content li[data-time=" + weekDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
$(".hours-content li[data-time=" + hourDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
$(".minutes-content li[data-time=" + minuteDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active");
} // 秒时每秒都需要更新的
$(".seconds-content li[data-time=" + secondDot + "]").parents("ul:first").children("li[class='active']").removeClass("active").end().end().addClass("active"); // 旋转圈数加一(解决360°转到0°时的bug)
hours === 11 ? rotateIndexH++ : 0;
minutes === 59 ? rotateIndexM++ : 0;
seconds === 59 ? rotateIndexS++ : 0; // 让函数一秒钟执行一次
var timer = setTimeout(run, 1000);
} // 干支纪年法
function toAncientYear(year) {
var sky = ["", "辛", "壬", "癸", "甲", "乙", "丙", "丁", "戊", "己", "庚"];
var land = ["", "酉", "戌", "亥", "子", "丑", "寅", "卯", "辰", "巳", "午", "未", "申"]; // 用年份除以10得数中余数相对应的便是天干
var one = year % 10;
// 用年份除以12得数中余数相对应的便是地支
var two = year % 12; var res = sky[one] + land[two];
return res;
} //时间转时辰
function toAncientHours(num) {
var res = "";
switch (num) {
case 1: res = "子"; break;
case 2: res = "丑"; break;
case 3: res = "寅"; break;
case 4: res = "卯"; break;
case 5: res = "辰"; break;
case 6: res = "巳"; break;
case 7: res = "午"; break;
case 8: res = "未"; break;
case 9: res = "申"; break;
case 10: res = "酉"; break;
case 11: res = "戌"; break;
case 12: res = "亥"; break;
}
return res;
}

欢迎交流学习。

转载请注明出处,谢谢!


源码地址 提取码:aiml

上一篇:poj 3630 Phone List(字典树)


下一篇:Delphi 7事件的多处理机制