Javascript 實現[網紅] 時間輪盤


話不多說,先上圖。

成品鏈接

大致效果如上圖,接下來就開始制作吧。

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 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM