zoukankan      html  css  js  c++  java
  • 从零开始学 Web 之 BOM(二)定时器

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新......

    在这里我会从 Web 前端零基础开始,一步步学习 Web 相关的知识点,期间也会分享一些好玩的项目。现在就让我们一起进入 Web 前端学习的冒险之旅吧!

    分割线

    一、定时器

    BOM 中有两中方式设置定时器。

    1、方式一

    特点:定时器可以重复使用。

    // 参数有两个:
    // 第一个参数:定时器定时结束处理函数
    // 第二个参数:定时事件,单位毫秒。
    // 返回值:定时器id值
    var timeId = window.setInterval(function() {
      // ...
    }, 1000); // 定时1s
    
    // 清除定时器
    // 参数只有一个:定时器的 id 值。
    window.clearInterval(timeId);
    

    1.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 动一次,点击停止按钮,图片停止移动。

    遗留问题:

    多次点击“摇起来”按钮的时候,图片动的越来越快,而且点击“停止”按钮没法停下来。

    原因分析:

    多次点击“摇起来”按钮的时候,timeId 的值会有多个,而停止的时候,只会清理最后一个值,其他的值对应的定时器没有清理。

    解决方法:

    在每次点击按钮的时候,先进行一次定时器的清理动作。clearInterval(timeId);

    2、方式二

    特点:定时器是一次性的。

    setTimeout(); // 参数与返回值同 setInterval();
    

    这个定时器只执行一次。虽然只执行一次,但是还是要清零,不然就一直占内存。

    clearTimeOut(); // 参数为 setTimeout() 定时器的 id。
    

    2.1、案例:协议禁用倒计时

    <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.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;
                 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>
    

    1、既然要缓慢移动,就需要定时器。

    2、当前位置的获取不能使用 element.style.left; 而需要使用 element.offsetLeft; 因为所有写在标签中的 style 属性值都拿不到,只有内联的 style 属性值可以使用 element.style.left 拿到。而 element.offsetLeft 则两种方式都可以拿到。

    3、需要每次移动的步数 onestep,而且有回退的需要,所以 onestep 可能是负数。

    4、每次移动后判断现在的位置到目标位置的距离,如果大于 onestep,那么就移动 当前 current 加减 onestep 的位置,否则就移动到目标位置,这样做的目的是避免 onestep 的不确定,导致最后的终点与目标还差少许的距离。

    5、使用当前与目标距离的绝对值来决定是前进还是后退。

    6、到达目标位置后,关闭定时器。

    7、将动画过程封装成一个函数,参数为移动的目标和移动的距离。

    8、注意:div 需要脱离文档流。

    2.3、案例:轮播图

    2.3.1、简单的轮播图

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <style>
            * {
                margin: 0;
                padding: 0;
            }
            #box {
                 400px;
                height: 250px;
                margin: 200px 0 0 400px;
                position: relative;
                border: 2px solid #31608a;
                overflow: hidden;
            }
            ul {
                 1300px;
                position: absolute;
            }
            li {
                list-style-type: none;
                float: left;
            }
            img {
                 400px;
                height: 250px;
            }
            li a {
                display: inline-block;
            }
            .sp {
                position: absolute;
                left: 50%;
                margin-left: -45px;
                bottom: 10px;
            }
            span {
                float: left;
                 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>
    

    1、移动的时候移动的是 ul,而不是单独的 li 或者 img。

    2、span 小标签在鼠标进入的时候,背景变成红色。(排他事件:需要两步,第一清理所有,第二当前元素设置属性)

    3、为每个 span 绑定事件时,程序开始,for 循环就运行完了,得不到每个span 标签的编号,所以要自定义属性保存每个 span 标签的编号。

    4、直接调用封装好的动画移动函数来移动 ul 标签。

    2.3.2、左右焦点轮播图

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

    1、首先获取所有需要的元素。

    2、使用克隆第一个 li 标签来模拟从最后一个图片切换到第一个图片的过程。注意:这时候 ul 的宽度要改变,保证 li 的浮动在一行显示。

    3、在右移最后一张过度到第二张的时候的处理方式为:当用户看到第一张的时候其实是最后一张,这个时候怎么过度到第二张?处理方法是,当在需要从最后一张跳转到第二张的时候,先让最后一张图切换到第一张,因为是克隆的,所以最后一张和第一张没有区别,用户看到的第一张其实是最后一张切换到了第一张,这个时候正常切换到第二张即可。

    4、当需要点击左右切换按钮,需要数字按钮相对应的时候,注意第一个数字按钮和最后一个数字按钮的特殊处理。

    5、图片下标 pos 是链接点击按钮和数字按钮的关键。

    6、设置自动播放的时候,不使用定时器设置 pos 的方式,是因为当前 pos 的值不确定,使用自动点击右移按钮的方式。之所以设置两个 setInterval(moveRight, 1000); ,一个是进入页面自动播放,一个是鼠标退出 box 后的自动播放。

    分割线

    Web前端之巅

  • 相关阅读:
    常州day2
    常州day3
    常州day1p3
    第3章 图像基础
    第2章 什么是深度学习?
    Deep Learning for Computer Vision with Python 第1章:整个内容简介
    双目视觉(1)---立体匹配介绍
    ubuntu 16.04 配置python远程jupyter nootbook环境
    Ubuntu16.04 Caffe CPU版本 安装步骤记录
    opencv(2)- 处理像素值
  • 原文地址:https://www.cnblogs.com/lvonve/p/9230755.html
Copyright © 2011-2022 走看看