從零開始學 Web 之 BOM(二)定時器

你們好,這裏是「 從零開始學 Web 系列教程 」,並在下列地址同步更新......javascript

在這裏我會從 Web 前端零基礎開始,一步步學習 Web 相關的知識點,期間也會分享一些好玩的項目。如今就讓咱們一塊兒進入 Web 前端學習的冒險之旅吧!css

分割線

1、定時器

BOM 中有兩中方式設置定時器。html

一、方式一

特色:定時器能夠重複使用。前端

// 參數有兩個:
// 第一個參數:定時器定時結束處理函數
// 第二個參數:定時事件,單位毫秒。
// 返回值:定時器id值
var timeId = window.setInterval(function() {
  // ...
}, 1000); // 定時1s

// 清除定時器
// 參數只有一個:定時器的 id 值。
window.clearInterval(timeId);

1.一、案例:圖片搖起來

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        div {
            position: absolute;
        }
    </style>
</head>
<body>
<input type="button" value="搖起來" id="btn1">
<input type="button" value="中止" id="btn2">
<div id="dv">
    <img src="images/Daotin.png" alt="">
</div>

<script src="common.js"></script>
<script>
    var timeId = 0;
    my$("btn1").onclick = function () {
        timeId = setInterval(function () {
            //讓圖片動起來可使div動起來
            var x = parseInt(Math.random() * 100) + 1; // 1-100隨機數
            var y = parseInt(Math.random() * 100) + 1;
            my$("dv").style.left = x + "px";
            my$("dv").style.top = y + "px";
        }, 100);
    };
    my$("btn2").onclick = function () {
        clearInterval(timeId);
    };
</script>
</body>
</html>

點擊」搖起來「按鈕,圖片每隔 100ms 動一次,點擊中止按鈕,圖片中止移動。java

遺留問題:git

屢次點擊「搖起來」按鈕的時候,圖片動的愈來愈快,並且點擊「中止」按鈕無法停下來。github

緣由分析:微信

屢次點擊「搖起來」按鈕的時候,timeId 的值會有多個,而中止的時候,只會清理最後一個值,其餘的值對應的定時器沒有清理。app

解決方法:dom

在每次點擊按鈕的時候,先進行一次定時器的清理動做。clearInterval(timeId);

二、方式二

特色:定時器是一次性的。

setTimeout(); // 參數與返回值同 setInterval();

這個定時器只執行一次。雖然只執行一次,可是仍是要清零,否則就一直佔內存。

clearTimeOut(); // 參數爲 setTimeout() 定時器的 id。

2.一、案例:協議禁用倒計時

<body>
<input type="button" value="請認真閱讀協議(5)" id="btn" disabled>

<script src="common.js"></script>
<script>
    var time = 5;
    var timeId = setInterval(function () {
        time--;
        if (time >= 0) {
            my$("btn").value = "請認真閱讀協議(" + time + ")";
        } else {
            clearInterval(timeId);
            my$("btn").value = "贊成";
            my$("btn").disabled = false;
        }
    }, 1000);
</script>
</body>

倒計時後才能夠點擊贊成按鈕。

2.二、案例:移動元素

目標:有兩個按鈕,點擊第一個按鈕,div 緩慢移動到 400px 位置,點擊第二個按鈕緩慢移動到 800px 位置,再點擊第一個按鈕緩慢移動到 400px 位置......

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        input {
            margin-top: 10px;
        }

        div {
            position: absolute;
            width: 200px;
            height: 100px;
            background-color: yellowgreen;
            margin-top: 10px;
            /*left: 20px;*/
        }
    </style>
</head>
<body>
<input type="button" value="移動400px" id="btn1">
<input type="button" value="移動800px" id="btn2">
<div id="dv"></div>

<script src="common.js"></script>
<script>
    // 移動400px
    my$("btn1").onclick = function () {
        animation(my$("dv"), 400);

    };
    // 移動800px
    my$("btn2").onclick = function () {
        animation(my$("dv"), 800);

    };

    // 封裝動畫移動函數
    function animation(element, target) {
        // 判斷當前的位置
        var current = element.offsetLeft; // 不能使用 element.style.left
        var onestep = 7;

        var timeId = setInterval(function () {
            current += current < target ? onestep : -onestep;
            if (Math.abs(current - target) >= onestep) {
                element.style.left = current + "px";
            } else {
                clearInterval(timeId);
                element.style.left = target + "px";
            }
        }, 20);
    }
</script>
</body>
</html>

一、既然要緩慢移動,就須要定時器。

二、當前位置的獲取不能使用 element.style.left; 而須要使用 element.offsetLeft; 由於全部寫在標籤中的 style 屬性值都拿不到,只有內聯的 style 屬性值可使用 element.style.left 拿到。而 element.offsetLeft 則兩種方式均可以拿到。

三、須要每次移動的步數 onestep,並且有回退的須要,因此 onestep 多是負數。

四、每次移動後判斷如今的位置到目標位置的距離,若是大於 onestep,那麼就移動 當前 current 加減 onestep 的位置,不然就移動到目標位置,這樣作的目的是避免 onestep 的不肯定,致使最後的終點與目標還差少量的距離。

五、使用當前與目標距離的絕對值來決定是前進仍是後退。

六、到達目標位置後,關閉定時器。

七、將動畫過程封裝成一個函數,參數爲移動的目標和移動的距離。

八、注意:div 須要脫離文檔流。

2.三、案例:輪播圖

2.3.一、簡單的輪播圖

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #box {
            width: 400px;
            height: 250px;
            margin: 200px 0 0 400px;
            position: relative;
            border: 2px solid #31608a;
            overflow: hidden;
        }
        ul {
            width: 1300px;
            position: absolute;
        }
        li {
            list-style-type: none;
            float: left;
        }
        img {
            width: 400px;
            height: 250px;
        }
        li a {
            display: inline-block;
        }
        .sp {
            position: absolute;
            left: 50%;
            margin-left: -45px;
            bottom: 10px;
        }
        span {
            float: left;
            width: 20px;
            height: 20px;
            background-color: #fff;
            border-radius: 10px;
            text-align: center;
            font: 400 16px/20px Consolas;
            margin: 0 5px 0 5px;
            cursor: pointer;
        }
        .current {
            background-color: red;
            color: #fff;
        }
    </style>
</head>
<body>
<div id="box">
    <ul>
        <li><a href="#"><img src="images/img1.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img2.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img3.jpg" alt=""></a></li>
    </ul>
    <div class="sp">
        <span class="current">1</span>
        <span>2</span>
        <span>3</span>
    </div>
</div>

<script src="common.js"></script>
<script>
    // 獲取box元素
    var boxObj = my$("box");

    // 獲取ul元素,由於移動的就是整個ul
    var ulObj = boxObj.children[0];

    // 移動寬度
    var moveWidth = document.getElementsByTagName("img")[0].offsetWidth;

    // 獲取全部span標籤
    var spanObjs = boxObj.children[1].getElementsByTagName("span");
    // console.log(spanObjs);

    for (var i = 0; i < spanObjs.length; i++) {
        // 獲取每一個span的編號,設置自定義屬性
        spanObjs[i].setAttribute("index", "" + i);

        spanObjs[i].onmouseover = function () {
            for (var j = 0; j < spanObjs.length; j++) {
                // 清空span背景
                spanObjs[j].removeAttribute("class");
            }
            // 設置當前span標籤
            this.className = "current";

            // 每一個編號*移動的寬度就是移動到的目標位置
            var index = this.getAttribute("index");
            animation(ulObj, -index*moveWidth);

        };
    }

    // 封裝動畫移動函數
    function animation(element, target) {
        // 判斷當前的位置
        var current = element.offsetLeft;
        var onestep = 7;
        var timeId = setInterval(function () {
            current += current < target ? onestep : -onestep;
            if (Math.abs(current - target) >= onestep) {
                element.style.left = current + "px";
            } else {
                clearInterval(timeId);
                element.style.left = target + "px";
            }
        }, 10);
    }
</script>
</body>
</html>

一、移動的時候移動的是 ul,而不是單獨的 li 或者 img。

二、span 小標籤在鼠標進入的時候,背景變成紅色。(排他事件:須要兩步,第一清理全部,第二當前元素設置屬性)

三、爲每一個 span 綁定事件時,程序開始,for 循環就運行完了,得不到每一個span 標籤的編號,因此要自定義屬性保存每一個 span 標籤的編號。

四、直接調用封裝好的動畫移動函數來移動 ul 標籤。

2.3.二、左右焦點輪播圖

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #box {
            width: 400px;
            height: 250px;
            margin: 200px 0 0 400px;
            position: relative;
            border: 2px solid #31608a;
            overflow: hidden;
        }
        ul {
            width: 1300px;
            position: absolute;
        }
        li {
            list-style-type: none;
            float: left;
        }
        img {
            width: 400px;
            height: 250px;
        }
        .sp {
            width: 400px;
            height: 50px;
            position: absolute;
            top: 100px;
            display: none;
        }
        #left {
            width: 50px;
            height: 50px;
            float: left;
            cursor:pointer;
            text-align:center;
            font: 400 28px/50px Consolas;
            background-color: #fff;
            opacity: 0.4;  /* 透明度 */

        }

        #right {
            float: right;
            width: 50px;
            height: 50px;
            cursor:pointer;
            text-align:center;
            font: 400 28px/50px Consolas;
            background-color: #fff;
            opacity: 0.4;
        }

    </style>
</head>
<body>
<div id="box">
    <ul>
        <li><a href="#"><img src="images/img1.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img2.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img3.jpg" alt=""></a></li>
    </ul>
    <div class="sp">
        <span id="left"><</span>
        <span id="right">></span>
    </div>
</div>

<script src="common.js"></script>
<script>
    // 獲取box元素
    var boxObj = my$("box");

    // 獲取ul元素,由於移動的就是整個ul
    var ulObj = boxObj.children[0];

    // 移動寬度
    var moveWidth = document.getElementsByTagName("img")[0].offsetWidth;

    // 獲取sp標籤
    var spObj =boxObj.children[1];

    // 獲取span左標籤
    var leftObj = my$("left");
    // 獲取span右標籤
    var rightObj = my$("right");

    var index = 0;

    boxObj.onmouseover = function () {
        spObj.style.display = "block";
    };
    boxObj.onmouseout = function () {
        spObj.style.display = "none";
    };

    // 左移
    leftObj.onclick = function () {
        if(index) {
            index--;
            animation(ulObj, -index*moveWidth);
        }
    };

    // 右移
    rightObj.onclick = function () {
        if(index<ulObj.children.length-1) {
            index++;
            animation(ulObj, -index*moveWidth);
        }
    };

    // 封裝動畫移動函數
    function animation(element, target) {
        // 判斷當前的位置
        var current = element.offsetLeft;
        var onestep = 17;
        var timeId = setInterval(function () {
            current += current < target ? onestep : -onestep;
            if (Math.abs(current - target) >= onestep) {
                element.style.left = current + "px";
            } else {
                clearInterval(timeId);
                element.style.left = target + "px";
            }
        }, 10);
    }
</script>
</body>
</html>

2.3.三、完整輪播圖

需求:鼠標進入數字按鈕自動切換;鼠標點擊左右切換按鈕切換,而且數字按鈕跟着切換;自動輪播。

代碼:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="base.css">
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        #box {
            width: 400px;
            height: 250px;
            margin: 100px 0 0 400px;
            position: relative;
            border: 2px solid #31608a;
            overflow: hidden;
        }

        ul {
            width: 1300px;
            position: absolute;
        }

        li {
            list-style-type: none;
            float: left;
        }

        img {
            width: 400px;
            height: 250px;
        }

        .sp {
            position: absolute;
            left: 50%;
            margin-left: -45px;
            bottom: 10px;
        }

        span {
            float: left;
            width: 20px;
            height: 20px;
            background-color: #fff;
            border-radius: 10px;
            text-align: center;
            font: 400 16px/20px Consolas;
            margin: 0 5px 0 5px;
            cursor: pointer;
        }

        .spdiv {
            width: 400px;
            height: 50px;
            position: absolute;
            top: 100px;
            display: none;
        }

        #left {
            width: 50px;
            height: 50px;
            float: left;
            cursor: pointer;
            text-align: center;
            font: 400 28px/50px Consolas;
            color: #fff;
            background-color: rgba(255, 255, 255, 0.3);

        }

        #right {
            float: right;
            width: 50px;
            height: 50px;
            cursor: pointer;
            text-align: center;
            font: 400 28px/50px Consolas;
            color: #fff;
            background-color: rgba(255, 255, 255, 0.3);
        }

        .current {
            background-color: red;
            color: #fff;
        }
    </style>
</head>
<body>
<div id="box">
    <ul>
        <li><a href="#"><img src="images/img1.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img2.jpg" alt=""></a></li>
        <li><a href="#"><img src="images/img3.jpg" alt=""></a></li>
    </ul>
    <div class="sp">
        <span class="current">1</span>
        <span>2</span>
        <span>3</span>
    </div>
    <div class="spdiv">
        <s id="left"><</s>
        <s id="right">></s>
    </div>
</div>

<script src="common.js"></script>
<script>
    // 獲取box元素
    var boxObj = my$("box");

    // 獲取ul元素,由於移動的就是整個ul
    var ulObj = boxObj.children[0];

    // 移動寬度
    var moveWidth = document.getElementsByTagName("img")[0].offsetWidth;

    // 獲取ul中全部的li
    var liObjs = ulObj.children;

    ulObj.appendChild(liObjs[0].cloneNode(true)); // 克隆第一個li,加入到ul中的最後
    ulObj.style.width = ulObj.offsetWidth + moveWidth + "px"; // 從新設置ul的寬度

    // 獲取全部span標籤
    var spanObjs = boxObj.children[1].getElementsByTagName("span");
    // console.log(spanObjs);

    // 獲取spdiv標籤
    var spdivObj = boxObj.children[2];
    // 獲取span左標籤
    var leftObj = my$("left");
    // 獲取span右標籤
    var rightObj = my$("right");

    var pos = 0;
    var myTimeId = setInterval(moveRight, 1000);
    
    // 自動播放 + 鼠標進入事件
    boxObj.onmouseover = function () {
        spdivObj.style.display = "block";
        clearInterval(myTimeId);

    };
    boxObj.onmouseout = function () {
        spdivObj.style.display = "none";
        myTimeId = setInterval(moveRight, 1000);
    };

    // 左移
    leftObj.onclick = function () {
        if (pos === 0) {
            pos = spanObjs.length;
            ulObj.style.left = -spanObjs.length * moveWidth + "px";
        }
        pos--;
        animation(ulObj, -pos * moveWidth);

        for (var i = 0; i < spanObjs.length; i++) {
            // 清空span背景
            spanObjs[i].removeAttribute("class");
        }
        // 設置當前span標籤
        spanObjs[pos].className = "current";
    };

    // 右移
    rightObj.onclick = moveRight;

    function moveRight() {
        if (pos === spanObjs.length) { // 在到達克隆的一張的時候,當即跳到第一張
            pos = 0;
            ulObj.style.left = 0 + "px";
        }

        pos++;
        animation(ulObj, -pos * moveWidth);

        if (pos === spanObjs.length) {
            spanObjs[0].className = "current";
            spanObjs[spanObjs.length - 1].className = "";
        } else {
            for (var i = 0; i < spanObjs.length; i++) {
                // 清空span背景
                spanObjs[i].removeAttribute("class");
            }
            // 設置當前span標籤
            spanObjs[pos].className = "current";
        }


    };


    // 遍歷全部的 span 標籤
    for (var i = 0; i < spanObjs.length; i++) {
        // 獲取每一個span的編號,設置自定義屬性
        spanObjs[i].setAttribute("index", i + "");

        spanObjs[i].onmouseover = function () {
            for (var j = 0; j < spanObjs.length; j++) {
                // 清空span背景
                spanObjs[j].removeAttribute("class");
            }
            // 設置當前span標籤
            this.className = "current";

            // 每一個編號*移動的寬度就是移動到的目標位置
            pos = this.getAttribute("index");
            if (pos) {
                animation(ulObj, -pos * moveWidth);
            } else {

            }

        };
    }

    // 封裝動畫移動函數
    function animation(element, target) {
        // 判斷當前的位置
        var current = element.offsetLeft;
        var onestep = 7;
        var timeId = setInterval(function () {
            current += current < target ? onestep : -onestep;
            if (Math.abs(current - target) >= onestep) {
                element.style.left = current + "px";
            } else {
                clearInterval(timeId);
                element.style.left = target + "px";
            }
        }, 10);
    }
</script>
</body>
</html>

一、首先獲取全部須要的元素。

二、使用克隆第一個 li 標籤來模擬從最後一個圖片切換到第一個圖片的過程。注意:這時候 ul 的寬度要改變,保證 li 的浮動在一行顯示。

三、在右移最後一張過分到第二張的時候的處理方式爲:當用戶看到第一張的時候實際上是最後一張,這個時候怎麼過分到第二張?處理方法是,當在須要從最後一張跳轉到第二張的時候,先讓最後一張圖切換到第一張,由於是克隆的,因此最後一張和第一張沒有區別,用戶看到的第一張實際上是最後一張切換到了第一張,這個時候正常切換到第二張便可。

四、當須要點擊左右切換按鈕,須要數字按鈕相對應的時候,注意第一個數字按鈕和最後一個數字按鈕的特殊處理。

五、圖片下標 pos 是連接點擊按鈕和數字按鈕的關鍵。

六、設置自動播放的時候,不使用定時器設置 pos 的方式,是由於當前 pos 的值不肯定,使用自動點擊右移按鈕的方式。之因此設置兩個 setInterval(moveRight, 1000); ,一個是進入頁面自動播放,一個是鼠標退出 box 後的自動播放。

分割線

Web前端之巔

相關文章
相關標籤/搜索