webApi05


小概

本章的学习内容大致有:定时器介绍及应用场景,offset家族介绍,实现匀速动画的封装。


1. 定时器的介绍

1.1 setInterval定时器(永久定时器)

1.定时器作用 : 一段代码 间隔时间 反复执行
2.定时器语法 :
开启定时器:
let timeID = setInterval(一段代码,间隔时间);
关闭定时器
clearInterval(timeID);
3.定时器注意点 :
setInterval()永久定时器 : 一但开启,间隔时间永久重复执行。只能手动清除。

  • 应用场景:倒计时秒杀
    <style>
        span{
            display: inline-block;
            width: 50px;
            height: 50px;
            text-align: center;
            line-height: 50px;
            font-size: 20px;
            background-color: #000;
            color: #fff;
        }
    </style>
</head>
<body>
    <span id="hour">01</span> :
    <span id="minute">22</span> :
    <span id="second">15</span>
    <script>
        /*需求分析
        开启定时器,间隔1s
            1.获取页面元素文本innerText : h,m,s
            2.s-- 
            3.如果s < 0,s = 59,m--
            4.如果m < 0,m = 59,h--
            5.如果h,m,s 小于10,则在前面加上0
            6.将计算好的h,m,s重新赋值给innerText(重新渲染DOM树)
            7.如果h,m,s 都为0,此时清除定时器
         */

        let timeID = setInterval(function(){
            //1.获取页面元素文本innerText : h,m,s
            /* 注意点: innerText获取的内容是string类型,为了方便数学计算最好转成number类型 */
            let h = +document.querySelector('#hour').innerText;
            let m = +document.querySelector('#minute').innerText;
            let s = +document.querySelector('#second').innerText;
            //2.s-- 
            s--;
            //3.如果s < 0,s = 59,m--
            if( s < 0){
                s = 59;
                m--;
            }; 
            //4.如果m < 0,m = 59,h--
            if( m < 0 ){
                m = 59;
                h--;
            };
            //5.如果h,m,s 小于10,则在前面加上0
            h = h < 10 ? '0' + h : h;
            m = m < 10 ? '0' + m : m;
            s = s < 10 ? '0' + s : s;

            //6.将计算好的h,m,s重新赋值给innerText(重新渲染DOM树)
            document.querySelector('#hour').innerText = h;
            document.querySelector('#minute').innerText = m;
            document.querySelector('#second').innerText = s;
            //7.如果h,m,s 都为0,此时清除定时器
            if( h == 0 && m == 0 && s == 0){
                clearInterval(timeID);
            };
        },1000);
    </script>

1.2 setTimeout定时器(一次定时器)

  • 语法与setInterval一致,区别是,setTimeout定时器开启后间隔时间只能执行一次,而setInterval定时器如果不关闭可以一直执行
        let pp = document.querySelector('#pp');

        let timeID = null;
        //开启
        document.querySelector('#btn1').onclick = function(){
            /**
            * @description: 开启定时器
            * @param {function}  一段代码(回调函数)
            * @param {number}  间隔时间  单位:毫秒ms
            * @return: timeID 定时器编号
            */
            timeID = setTimeout(function(){
                pp.innerText++;
            },5000);

        };

        //关闭
        document.querySelector('#btn2').onclick = function(){
            /**
            * @description:关闭定时器
            * @param {number} 定时器ID
                * 每开启一个定时器,编译器就会给这个定时器一个编号(用于区分不同定时器),称之为定时器id
            * @return: 
            */
            clearTimeout(timeID);
        };

2. offset属性介绍

offset家族:获取元素自身’真实’宽高与位置

  1. offsetwideth / offsetHeight :获取元素真实宽高 = content + padding + border
  2. offsetParent:获取元素最近的父级定位
    2.1 如果一个元素是固定定位fixed,则定位父级是null
    2.2 如果一个元素是非固定定位(absolute,relative,static),且所有的父级元素都没有定位,则定位父级是body
    2.3 body的定位父级 是 null
  3. offsetLeft / offsetTop: 获取子元素 左/上 内边框 到 定位父级 左/上 外边框距离

注意
获取:不仅可以获取行内属性,也可获取行外属性(点语法则不能获取行外属性)。
数据类型:number类型,不带单位(点语法返回值是string类型,带单位)。
设置:只能获取,不能设置(点语法可以设置任何属性)。

    <style>
        .one{
            top:50px;
            left: 50px;
            width: 100px;
            height: 100px;
            background: greenyellow;
            border: 10px solid red;
            margin: 20px;   /*offsetLeft/offsetTop=50+20 px */
            position: absolute;
        }
        .two{
            top: 200px;
            left: 200px;
            width: 200px;
            height: 200px;
            background: cyan;
            border: 20px solid purple;
            padding: 10px;
            position: absolute;
        }

    </style>
</head>
<body>
    <div class="two">
        <div class="one" id="box">1</div>
    </div>
    <script>
        let box = document.querySelector('#box');

        //真实位置 = left/top + margin
        console.log( box.offsetLeft,box.offsetTop );//70 70
        
        //offsetParent
        console.log( box.offsetParent );  //class:two
        console.log( document.body.offsetParent );//null
     </script>

3. 动画

3.1 动画介绍

  • 原理:利用永久定时器给带定位的元素的left值 累加,letf值满足位置后用clearInterval()清除定时器、
        /* 
        1.动画原理 :速度  距离/时间   m/s     px/ms   
            * 元素移动原理: 有速度  单位时间ms  移动 单位距离px

        2.动画核心思路 
            开启定时器,让元素单位时间移动单位距离
         */
        let box = document.querySelector('.box');

        let currentLeft = 0;
        let timeID = null;
        //移动400
        document.querySelector('#btn1').onclick = function(){

            //1.开始动画
            timeID = setInterval(function(){
                //2.1 开始移动
                currentLeft += 18;
                console.log( currentLeft );
                box.style.left = currentLeft + 'px';
                //2.2 边界检测 : 超过边界则停止移动
                if( currentLeft >= 400 ){
                    //停止移动
                    clearInterval(timeID);
                    //元素复位 : 每一次移动的距离 和 目标位置不一定能整除,所以会产生误差
                    box.style.left = '400px';
                };
                
            },20);
        };
    </script>

3.2 匀速动画封装(移动距离不限)

匀速动画封装思路
1.解决动画代码冗余 -> 函数
2.解决距离不限 -> 参数
3.解决元素不限 -> 参数
4.解决方向不限

    <style>
        .box{
            width: 200px;
            height: 200px;
            background-color: red;

            position: absolute;
            left: 88px;
        }
    </style>
</head>
<body>
    <button id="btn1">移动到400</button>
    <button id="btn2">移动到800</button>
    <div class="box"></div>
    <script>
        let box = document.querySelector('.box');

        //移动400
        document.querySelector('#btn1').onclick = function(){
            animationMove(400);
        };

         //移动800
         document.querySelector('#btn2').onclick = function(){
            animationMove(800);
        };

        let timeID = null;
        function animationMove(target){
            //1.开始动画之前先清除之前的定时器,以本次移动为准
            clearInterval(timeID);
            //2.开始本次动画
            timeID = setInterval(function(){
                //2.1 获取元素当前位置
                let currentLeft = box.offsetLeft;
                //2.2 开始移动
                currentLeft += 10;
                box.style.left = currentLeft + 'px';
                //2.3 边界检测
                if( currentLeft >= target ){
                    //停止动画
                    clearInterval(timeID);
                    //元素复位
                    box.style.left = target + 'px';
                };
            },20);
        };
    </script>

遇到的问题:如果连续触发定时器(快速点击btn),会使动画平移速度变快
解决方法:在函数内部,定时器开始前,先清除之前的定时器clearInterval(timeID);

3.3 匀速动画封装(移动元素不限)

    <style>
        .box{
            width: 100px;
            height: 100px;
            background-color: red;

            position: absolute;
            left: 88px;
        }
        .box1{
            width: 100px;
            height: 100px;
            background-color: green;

            position: absolute;
            left: 0px;
            top: 150px;
        }
    </style>
</head>
<body>
    <button id="btn1">移动到400</button>
    <button id="btn2">移动到800</button>
    <div class="box"></div>
    <div class="box1"></div>

    <script>
        let box = document.querySelector('.box');
        let box1 = document.querySelector('.box1');

        //红色移动400
        document.querySelector('#btn1').onclick = function(){
            animationMove(400,box);
        };

         //绿色移动800
         document.querySelector('#btn2').onclick = function(){
            animationMove(800,box1);
        };

        /**
        * @description:匀速动画
        * @param {number}target : 目标位置 
        * @param {dom}ele : 目标元素 
        * @return: 
        */
        function animationMove(target,ele){
            //1.开始动画之前先清除之前的定时器,以本次移动为准
            clearInterval(ele.timeID);
            //2.开始本次动画
            /* 
            问题: 多个元素无法同时移动
            分析: 多个元素移动,需要多个定时器同时工作。 而timeID变量一次只能存储一个定时器
            解决: 存储多个定时器(每一个元素都需要一个存储定时器)
                数组 : 存储多个数据,但是阅读性不高
                对象: 存储多个数据,阅读性高(自定义属性存储定时器id)
            */
            ele.timeID = setInterval(function(){
                //2.1 获取元素当前位置
                let currentLeft = ele.offsetLeft;
                //2.2 开始移动
                currentLeft += 10;
                ele.style.left = currentLeft + 'px';
                //2.3 边界检测
                if( currentLeft >= target ){
                    //停止动画
                    clearInterval(ele.timeID);
                    //元素复位
                    ele.style.left = target + 'px';
                };
            },20);
        };

遇到的问题:因为每次调用函数都会清除之前的定时器,每次只能执行一个定时器,无法同时使用。
解决方法:通过对象的自定义属性存储定时器id,ele.timeID = setInterval(function(){});clearInterval(ele.timeID)、

3.4 匀速动画封装(移动方向不限)

         function animationMove(target, ele) {
             //1.开始动画之前先清除之前的定时器,以本次移动为准
             clearInterval(ele.timeID);
             //2.开始本次动画
             ele.timeID = setInterval(function () {
                 //2.1 获取元素当前位置
                 let currentLeft = ele.offsetLeft;
                 /* 使用布尔类型存储移动方向 true:从左往右  false:从右往左*/
                 let isLeft = target >= currentLeft ? true : false;
                 //2.2 开始移动
                 isLeft ? currentLeft += 10 : currentLeft -= 10;
                 ele.style.left = currentLeft + 'px';
                 //2.3 边界检测
                 if (isLeft ? currentLeft >= target : currentLeft <= target) {
                     //停止动画
                     clearInterval(ele.timeID);
                     //元素复位
                     ele.style.left = target + 'px';
                 };
             }, 20);
         };

判断移动的方向:元素当前位置>left值(target距离)则平移方向向左,自身offsetLeft递减到left值;元素当前位置<left值(target距离),则向右平移,自身offsetLeft递增到left值。

总结

匀速动画封装中判断方向稍微复杂一些,红色字体是我自身的一些理解,如果有表述不对的,希望有大佬及时指点、

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值