JavaScript学习笔记 06、DOM元素—③定时器与延时器(二)

简介: JavaScript学习笔记 06、DOM元素—③定时器与延时器(二)

四、定时器实现动画


4.1、js实现动画(不推荐)


需求:使用js来实现盒子的移动。从40px -> 600px,2s。


弊端:若是仅仅通过使用js来实现动画,这是十分麻烦的,例如你想要2s实现的一个动画,你需要去计算每秒其移动多少距离,每秒移动多少次,这需要进行大量计算,并且若是你还想设置返回动画,那就还需要进行更多的逻辑判断。


现在有许多的一些三方库给我们封装好,如jquery等。更好的方式还是js+css动画来进行配合使用!



<style>
    * {
        margin: 0;
        padding: 0;
    }
    div.box {
        width: 100px;
        height: 100px;
        border: 1px solid #000;
        background-color: orange;
        margin: 40px;
    }
</style>
<body>
    <div class="box" id="box"></div>
    <script>
        var m_box = document.getElementById("box");
        var left = 30;
        m_box.onclick = function () {
            var myInterval = setInterval(function () {
                left += 2;
                //设置盒子停止时机
                if (left >= 600) {
                    //指定到600px停止,清除定时器
                    clearInterval(myInterval);
                }
                m_box.style.marginLeft = left + "px";
            }, 7);
            //一秒中执行50次,预计设想2秒移动  => 移动距离560px。
            //1s就是280px,每次移动2px,那就是1s移动140次;1分钟1000毫秒,那就是设置7ms一次。
        };
    </script>
</body>




4.2、js+css配合实现动画


实现盒子左右移动(过渡+基本判断)

需求:我们点击一个按钮,让盒子移动到右边,再点击一下盒子移动到左边。



分析:


使用css动画来实现过渡效果:m_box.style.transition = "all 2s linear 0s";。

对于点击从左到右、从右到左通过js来进行控制。(通过判断postion属性来进行操作)

源码:


<style>
    * {
        margin: 0;
        padding: 0;
    }
    div.box {
        position: absolute;
        top: 30px;
        left: 40px;
        width: 100px;
        height: 100px;
        border: 1px solid #000;
        background-color: orange;
    }
</style>
<body>
    <button>点我移动</button>
    <div class="box" id="box"></div>
    <script>
        var m_button = document.getElementsByTagName("button")[0];
        var m_box = document.getElementById("box");
        var position = 0;//0:左边,1:右边
        m_button.onclick = function () {
            //1、使用css动画来实现过渡效果
            m_box.style.transition = "all 2s linear 0s";
            //2、js来编程进行左右的移动效果
            if (position == 0) {
                m_box.style.left = "1000px";
                position = 1;
            } else if (position == 1) {
                m_box.style.left = "40px";
                position = 0;
            }
        };
    </script>
</body>



案例出现问题(通过函数节流解决)

问题抛出


问题说明:虽说上面实现了通过按钮点击进行盒子的左右移动效果,但是若是我们在该盒子移动过程中多次去点击按钮,就会出现下面情况。


按理说是要先移动到右边,再进行移动到左边,可是中途进行点击就会一下子立马又向左移,我们如何来实现向左或向右完整执行2s再进行相反的移动呢?



解决方案:使用函数节流


函数节流:该名词是这样定义的,当一个函数执行一次后,只有大于设定的执行周期后才允许执行第二次。


固定模板:


var lock = true;//默认为true,表示开锁,允许进行下一步操作了
function 指定需要函数节流函数(){
  //如果当前为false(表示已经上锁),不往下执行
    if(!lock) return; //函数结束
  //关锁
    lock = false;
    xxx; //一些业务操作
    //使用延时器来等待2秒后开锁(时间根据指定情况来定),到时间了就开锁
    setTimeout(function(){
        lock = true;
    },2000);
}


优化上面的左右移动案例:只有动画执行完之后点击才有效(通过使用上方模板)



<style>
    * {
        margin: 0;
        padding: 0;
    }
    div.box {
        position: absolute;
        top: 30px;
        left: 40px;
        width: 100px;
        height: 100px;
        border: 1px solid #000;
        background-color: orange;
    }
</style>
<body>
    <button>点我移动</button>
    <div class="box" id="box"></div>
    <script>
        var m_button = document.getElementsByTagName("button")[0];
        var m_box = document.getElementById("box");
        var position = 0;//0:左边,1:右边
        //1、锁:true为开锁,false为上锁
        var lock = true;
        m_button.onclick = function () {
            //2、若是lock为false,表示上锁,直接退出函数
            if (!lock) return;
            //3、若是lock为true表示现在开着锁,继续向下执行,这里设置为false,表示此时在执行业务所以上锁
            lock = false;
            m_box.style.transition = "all 2s linear 0s";
            if (position == 0) {
                m_box.style.left = "1000px";
                position = 1;
            } else if (position == 1) {
                m_box.style.left = "40px";
                position = 0;
            }
            //4、使用延时器,由于动画是2s,所以这里设置2s后开锁!
            setTimeout(function () {
                lock = true;
            }, 2000);
        };
    </script>
</body>




实际案例

1、无缝连续滚动特效

效果与分析


需求:制作一个展示栏,展示栏中有多张图片(这里使用小盒子来替代),会不断进行连续滚动。当鼠标触碰进盒子就会暂停,离开盒子就会继续连续滚动。



思路分析:


首先是结构分析:外层使用了一个盒子,内部是ul的列表(使用了左浮动)。其中其中的div外盒子设置宽度为300px,但是为了让li元素都在一行上,就需要设置ul的宽度为1300px。


<div class="box">
    <ul>
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>
        <li>5</li>
        <li>6</li>
        <li>7</li>
    </ul>
</div>


我们来剖析一下原理:


我们把div的overflow: hidden取消,你就可以看到真面目了,里面有两倍的盒子(方便每一个盒子都能被看到),通过使用定时器来实现整个盒子的移动,并没有使用css的动画属性,当定时器中盒子到达指定left位置时,就重新设置left=0,重新进行循环进行。



额外说明的是:本次案例添加了两个事件,一个是鼠标移入,另一个是鼠标移出,分别是对定时器的设置与清除。



源码


<style>
    * {
        margin: 0;
        padding: 0;
    }
    div.box {
        position: relative;
        width: 300px;
        height: 62px;
        overflow: hidden;
        border: 1px solid #000;
        margin: 20px auto;
    }
    div.box ul {
        position: absolute;
        /*0一直到-330px表示一趟结束  */
        left: 0;
        list-style: none;
        /* 设置内部的ul宽度大一些,来支撑原本内部元素的长度 */
        width: 1300px;
    }
    div.box li {
        float: left;
        height: 60px;
        width: 80px;
        border: 1px solid #000;
        text-align: center;
        line-height: 60px;
        margin-right: 10px;
        background-color: orange;
    }
    div.box li:nth-child(1) {
        background-color: red;
    }
    div.box li:nth-child(2) {
        background-color: blue;
    }
    div.box li:nth-child(3) {
        background-color: green;
    }
    div.box li:nth-child(4) {
        background-color: gold;
    }
    div.box li:nth-child(5) {
        background-color: goldenrod;
    }
    div.box li:nth-child(6) {
        background-color: orange;
    }
    div.box li:nth-child(7) {
        background-color: gray;
    }
</style>
<body>
    <div class="box">
        <ul>
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
            <li>7</li>
        </ul>
    </div>
    <script>
        var m_ul = document.getElementsByTagName("ul")[0];
        //复制一份待移动的多个小盒子(方便每个盒子都能够预览到)
        m_ul.innerHTML += m_ul.innerHTML;
        //全局变量:ul左边距离
        var l = 0;
        //全局变量:定时器的ID号
        var inervalID
        //创建定时器
        function setShowInterval() {
            clearInterval(inervalID);//一定要记得清除事件
            //设置定时器
            inervalID = setInterval(function () {
                l -= 4;
                if (l <= -850) {
                    l = 0;
                }
                m_ul.style.left = l + "px";
            }, 20);
        }
        //初始化时要创建定时器
        setShowInterval();
        //鼠标移入与移除事件
        //为ul设置鼠标移入事件:定时器停止
        m_ul.onmouseenter = function () {
            clearInterval(inervalID);
        }
        //为ul设置鼠标移出事件:设置定时器
        m_ul.onmouseleave = function () {
            setShowInterval();
        }
    </script>
</body>



2、跑马灯轮播图(左右翻图)

实际原理与案例1的无缝连续滚动相同,只不过这里将第一个图片多复制了一份到后面。


使用到的知识点如:


克隆节点+点击事件,css+js配合实现动画效果。

对于前后切换图片(快速无痕切换),需要将transication属性在none、all .5s ease 0s两者间进行切换。

函数节点(控制动画效果能够顺利完成)。

效果展示:点击左右按钮实现图片翻页



源码:


<style>
    * {
        margin: 0;
        padding: 0;
        font-size: large;
        font-weight: bolder;
    }
    div.box {
        position: relative;
        width: 350px;
        height: 230px;
        margin: 20px auto;
        border: 1px solid #000;
        overflow: hidden;
    }
    div.box ul {
        list-style: none;
        /* 350*5=1750 */
        width: 1750px;
        position: absolute;
        left: 0;
    }
    div.box ul li {
        float: left;
    }
    img {
        width: 350px;
        height: 230px;
    }
    a {
        text-decoration: none;
        position: absolute;
        width: 30px;
        height: 30px;
        border-radius: 15px;
        background-color: rgba(255, 255, 255, .5);
        text-align: center;
        line-height: 30px;
    }
    a:nth-of-type(1) {
        top: 50%;
        left: 0;
        margin-top: -15px;
    }
    a:nth-of-type(2) {
        top: 50%;
        right: 0;
        margin-top: -15px;
    }
</style>
<body>
    <div class="box">
        <ul>
            <li><img src="./images/img_01.jpg" alt=""></li>
            <li><img src="./images/img_02.jpg" alt=""></li>
            <li><img src="./images/img_03.jpg" alt=""></li>
            <li><img src="./images/img_04.jpg" alt=""></li>
        </ul>
        <a href="javascript:;">&lt;</a>
        <a href="javascript:;">&gt;</a>
    </div>
    <script>
        //宽为230px
        //两个按钮节点
        var firstA = document.getElementsByTagName("a")[0];
        var secondA = document.getElementsByTagName("a")[1];
        //ul元素
        var myul = document.getElementsByTagName("ul")[0]
        var currentImgPos = 0;//表示第几张图片
        //为ul结尾添加第一张图
        myul.appendChild(document.getElementsByTagName("li")[0].cloneNode(true));
        //用于函数节点操作
        var lock = true;
        //给左按钮绑定单击事件
        firstA.onclick = function () {
            if (!lock) return;
            lock = false;
            myul.style.transition = "all .5s ease 0s";
            currentImgPos++;
            //若是已经到达了第五张图,通过使用延时器来快速回到原本位置
            if (currentImgPos == 4) {
                //使用延时器恢复原来的过渡效果
                setTimeout(function () {
                    myul.style.transition = "none";
                    currentImgPos = 0;
                    myul.style.left = 0 + "px";
                }, 500);
            }
            myul.style.left = -currentImgPos * 350 + "px";
            //设置0.5s(与切换一张图片相同时长释放锁)
            setTimeout(function () {
                lock = true;
            }, 500)
        };
        // 点击右边按钮
        secondA.onclick = function () {
            if (!lock) return;
            lock = false;
            //一旦图片是第一张往前移
            if (currentImgPos == 0) {
                // 快速移动到最后一张图片上
                myul.style.transition = "none";
                myul.style.left = -4 * 350 + "px";
                //这个延时器就设置为0s,在其后进行向前移动效果(含过渡)
                setTimeout(function () {
                    myul.style.transition = "all .5s ease 0s";
                    currentImgPos = 3;
                    myul.style.left = -currentImgPos * 350 + "px";
                }, 0);
            } else {
                //正常向前移动
                currentImgPos--;
                myul.style.left = -currentImgPos * 350 + "px";
            }
            //设置0.5s(与切换一张图片相同时长释放锁)
            setTimeout(function () {
                lock = true;
            }, 500)
        }
    </script>
</body>




3、呼吸轮播图

分析:同样也是轮播图,通过点击左右按钮的方式来进行淡入淡出的。想要制作出这类效果,需要将多张图片全部堆叠在一起,初始三张图片设置透明度为0,另外一张透明度为1。之后对透明度参数设置过渡效果实现!



源码:


<style>
    * {
        margin: 0;
        padding: 0;
        font-size: large;
        font-weight: bolder;
    }
    div.box {
        position: relative;
        width: 350px;
        height: 230px;
        margin: 20px auto;
        border: 1px solid #000;
        /* overflow: hidden; */
    }
    div.box ul {
        list-style: none;
        /* 350*5=1750 */
        width: 1750px;
        position: absolute;
        left: 0;
    }
    div.box ul li {
        position: absolute;
        left: 0;
        top: 0;
        /* 透明度为0 */
        opacity: 0;
        transition: all 1s linear 0s;
    }
    div.box ul li:nth-child(1) {
        /* 透明度为1 */
        opacity: 1;
    }
    img {
        width: 350px;
        height: 230px;
    }
    a {
        text-decoration: none;
        position: absolute;
        width: 30px;
        height: 30px;
        border-radius: 15px;
        background-color: rgba(255, 255, 255, .5);
        text-align: center;
        line-height: 30px;
    }
    a:nth-of-type(1) {
        top: 50%;
        left: 0;
        margin-top: -15px;
    }
    a:nth-of-type(2) {
        top: 50%;
        right: 0;
        margin-top: -15px;
    }
</style>
<body>
    <div class="box">
        <ul>
            <li><img src="./images/img_01.jpg" alt=""></li>
            <li><img src="./images/img_02.jpg" alt=""></li>
            <li><img src="./images/img_03.jpg" alt=""></li>
            <li><img src="./images/img_04.jpg" alt=""></li>
        </ul>
        <a href="javascript:;">&lt;</a>
        <a href="javascript:;">&gt;</a>
    </div>
    <script>
        //宽为230px
        //两个按钮节点
        var firstA = document.getElementsByTagName("a")[0];
        var secondA = document.getElementsByTagName("a")[1];
        //li元素
        var lists = document.getElementsByTagName("li");
        var pos = 0;//表示当前照片的位置
        //用于函数节点操作
        var lock = true;
        //给左按钮绑定单击事件
        firstA.onclick = function () {
            if (!lock) return;
            lock = false;
            //老图淡出
            lists[pos].style.opacity = 0;
            pos++;
            if (pos > 3) {
                pos = 0;
            }
            //新图淡入
            lists[pos].style.opacity = 1;
            setTimeout(function () {
                lock = true;
            }, 1000);
        };
        //给右按钮绑定单击事件
        secondA.onclick = function () {
            if (!lock) return;
            lock = false;
            //老图淡出
            lists[pos].style.opacity = 0;
            pos--;
            if (pos < 0) {
                pos = 3;
            }
            //新图淡入
            lists[pos].style.opacity = 1;
            setTimeout(function () {
                lock = true;
            }, 1000);
        };
    </script>
</body>


相关文章
|
11月前
|
JavaScript 算法 开发者
如何用JS实现在网页上通过鼠标移动批量选择元素的效果?
本文介绍了类似电脑桌面通过鼠标选择多个图标的实现原理。主要通过监听mousedown、mousemove和mouseup事件,动态调整选择框大小并计算与元素的重叠情况。提供了角重叠和相交重叠的检测方法,并附有示例代码和在线演示链接,方便开发者参考与测试。
376 56
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
475 1
|
JavaScript 前端开发 API
JavaScript中通过array.map()实现数据转换、创建派生数组、异步数据流处理、复杂API请求、DOM操作、搜索和过滤等,array.map()的使用详解(附实际应用代码)
array.map()可以用来数据转换、创建派生数组、应用函数、链式调用、异步数据流处理、复杂API请求梳理、提供DOM操作、用来搜索和过滤等,比for好用太多了,主要是写法简单,并且非常直观,并且能提升代码的可读性,也就提升了Long Term代码的可维护性。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
移动开发 运维 供应链
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
供应链 JavaScript 前端开发
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
746 5
|
JavaScript 前端开发 开发者
.js的dom元素操作
【10月更文挑战第29天】通过灵活运用这些 DOM 元素操作方法,JavaScript 可以实现丰富的网页交互效果,如动态更新页面内容、响应用户操作、创建和删除页面元素等。在实际开发中,开发者可以根据具体的需求和场景,选择合适的 DOM 元素操作方法来实现所需的功能,为用户提供更加流畅和动态的网页体验。
|
JavaScript
DOM 节点列表长度(Node List Length)
DOM 节点列表长度(Node List Length)
|
JavaScript
HTML DOM 节点树
HTML DOM 节点是指在 HTML 文档对象模型中,文档中的所有内容都被视为节点。整个文档是一个文档节点,每个 HTML 元素是元素节点,元素内的文本是文本节点,属性是属性节点,注释是注释节点。DOM 将文档表示为节点树,节点之间有父子和同胞关系。