話不多說,先上圖。
成品鏈接
大致效果如上圖,接下來就開始制作吧。
HTML部分:
我們需要將容器旋轉rotate使之以圓點為中心。
怎么轉呢,請看圖。
將同一級的容器用一個大的容器包裹起來,絕對定位。這時,所有的子容器會重合在一起。
然后我們用360°去除以子容器個數,可以得到每個子容器的角度差,采用角度差來旋轉每個容器。
效果如圖:
我們可以看到,他是重合在一起的,應位默認的旋轉中心是容器的中心,
這時我們需要改變旋轉中心點,
添加css屬性 transform-origin: -50% 50%;
效果如圖:
我們可以發現此時旋轉過后的圖形超出了父容器,所以需要改變他的位置,根據旋轉可知。
圖形總長度為子容器長度的3倍(中間空白處為一個子容器長度)
高度為 空白處高度加上 子容器高度的兩倍
經過位置變換(再填上文字)
效果如圖:
以上講解代碼如下:
<!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: 0; margin: 0; 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: 9; } .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: 8; } .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: 7; } .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: 6; } .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: 10; } .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