【学习笔记54】运动函数的分析

news2024/10/6 22:20:34

一、运动函数的基本实现

  • 运动函数是我们自己封装的一个函数。
  • 作用是将css样式的改变不是一次性完成,是逐步完成执行效果,看上去像是动画/运动完成的css样式改变。
  • 实际项目中框架等都有自己的运动函数我们目前封装一个简单的兼容多属性的运动函数。

1、HTML和CSS代码

    <div class="box1"></div>
    <div class="box2"></div>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        .box1 {
            width: 100px;
            height: 100px;
            background-color: pink;
            position: absolute;
            top: 0;
            left: 100;
        }

        .box2 {
            width: 100px;
            height: 100px;
            background-color: green;
            position: absolute;
            top: 200px;
            left: 0;
        }
    </style>

3、代码的实现

        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        oDiv1.onclick = function () {
            // 定义变量 用与步长的累加
            let count = 0;

            // 定时器的this指向是window 改变this指向
            const that = this;

            // 定时器
            const timer = setInterval(function () {
                count += 5;
                that.style.left = count + 'px';

                // 清除定时器
                if (count == 100) {
                    clearInterval(timer);
                }
            }, 50)
        }

        
        oDiv2.onclick = function () {
            // 定义变量 用与步长的累加
            let count = 0;

            // 定时器的this指向是window 改变this指向
            const that = this;

            // 定时器
            const timer = setInterval(function () {
                count += 5;
                that.style.left = count + 'px';

                // 清除定时器
                if (count == 100) {
                    clearInterval(timer);
                }
            }, 50)
        }

二、封装函数

        // 封装函数
        function move(element, type, target) {
            /**
             *  @param      element      移动的标签对象
             *  @param      type         标签属性属性
             *  @param      target       移动的目标距离
            */
            // 定义变量 用与步长的累加
            let count = 0;

            // 定时器
            const timer = setInterval(function () {
                
                count += 5;
                
                element.style[type] = count + 'px';

                // 清除定时器
                if (count == target) {
                    clearInterval(timer);
                }
            }, 50)
        }

        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, 'left', 200)
        })
   
        oDiv2.addEventListener('click', function () {
            move(oDiv2, 'left', 400)
        })

三、代码优化

(一)优化一

  1. 问题: 每次运动都从0的位置开始移动
  2. 原因: 运动函数的 初始值, 是从0开始的
  3. 解决: 获取到元素本身值, 然后再次基础上移动

在这里插入图片描述

        // 封装函数
        function move(element, type, target) {
            /**
             *  @param      element      移动的标签对象
             *  @param      type         标签属性属性
             *  @param      target       移动的目标距离
            */
            // 定义变量 用与步长的累加
            let count = parseInt(window.getComputedStyle(element)[type]);
            console.log(count );
            // 定时器
            const timer = setInterval(function () {
                
                count += 5;
                
                element.style[type] = count + 'px';

                // 清除定时器
                if (count == target) {
                    clearInterval(timer);
                }
            }, 50)
        }

        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, 'left', 200)
        })
   
        oDiv2.addEventListener('click', function () {
            move(oDiv2, 'top', 400)
        })

在这里插入图片描述

(二)优化二

1、问题: 从200移动到501时, 不会停止
在这里插入图片描述

2、原因: 移动距离, 不是每次移动的整倍数;移动距离301(501-200),是每次运动的整倍数

3、解决
在这里插入图片描述

4、代码实现

        // 封装函数
        function move(element, type, target) {
            /**
             *  @param      element      移动的标签对象
             *  @param      type         标签属性属性
             *  @param      target       移动的目标距离
            */

            // 定时器
            const timer = setInterval(function () {
                // 获取当前的位置
                let count = parseInt(window.getComputedStyle(element)[type]);

                // 计算要移动的距离 (目标 - 当前的值) / 10
                let des = (target - count) / 10;

                // 判断是否需要继续移动
                if (target === count) {
                    // 此时说明移动到了, 可以结束定时器
                    clearInterval(timer);
                } else {
                    // 此时说明还没有移动到, 需要继续移动
                    element.style[type] = count + des + 'px';
                }
            }, 20)
        }

        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, 'left', 501)
        })

        oDiv2.addEventListener('click', function () {
            move(oDiv2, 'left', 100)
        })

(三)优化三

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

        // 封装函数
        function move(element, type, target) {
            /**
             *  @param      element      移动的标签对象
             *  @param      type         标签属性属性
             *  @param      target       移动的目标距离
            */

            // 定时器
            const timer = setInterval(function () {
                // 获取当前的位置
                let count = parseInt(window.getComputedStyle(element)[type]);

                // 计算要移动的距离 (目标 - 当前的值) / 10
                let des = (target - count) / 10;

                // 大于0向上取整 小于0向下取整
                des = des > 0 ? Math.ceil(des) : Math.floor(des);
                
                // 判断是否需要继续移动
                if (target === count) {

                    // 此时说明移动到了, 可以结束定时器
                    clearInterval(timer);
                } else {

                    // 此时说明还没有移动到, 需要继续移动
                    element.style[type] = count + des + 'px';
                }
            }, 20)
        }

        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, 'left', 0)
        })

        oDiv2.addEventListener('click', function () {
            move(oDiv2, 'left', 200)
        })

在这里插入图片描述

四、兼容透明度

        /**
         *  问题: 透明没有调整
         * 
         *  原因: 透明度没有单位
         * 
         *  解决: 在赋值的时候, 判断如果时透明度, 那么就别带单位
         * 
         *  新问题: 没有运动过程
         * 
         *  原因: 因为做了取整之后, 得到的值, 只会是 -1或者1
         * 
         *  解决: 想个办法, 将值放大
        */
            // 封装函数
            function move(element, type, target) {
            // 透明度 0.1 --> 1
            if(type === 'opacity') target *= 100;
            // target === 100

            let timer = setInterval(function(){
                // 获取当前位置的值  兼容透明度
                let count = type == 'opacity' ? window.getComputedStyle(element)[type]*100 : parseInt(window.getComputedStyle(element)[type]);
                // count === 0.1 * 100 === 10
                // 计算要移动的距离
                let des = (target - count) / 10;
                // destination == (target - count) / 10 === (100 - 10) / 10  === 9
                des = des > 0 ? Math.ceil(des) : Math.floor(des);
                // destination === 9
                // 清除定时器
                if(des === count){
                    
                    clearInterval(timer);
                }else{
                    
                    if(type === 'opacity'){
                        // (count + destination) / 100  === (10 + 9) / 100  === 19 / 100    === 0.19
                        element.style[type] = (count + des) / 100;
                    }else{
                        element.style[type] = count + des + 'px';
                    }
                }
            })
        }

        // 获取标签对象
        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');
        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, 'opacity', 1)
        })

        oDiv2.addEventListener('click', function () {
            move(oDiv2, 'left', 200)
            move(oDiv2, 'opacity', 1)
        })

在这里插入图片描述

五、有多个属性时

  1. 问题:开启多个属性运动时,需要调用多次
  2. 原因:参数是固定的
  3. 解决:多个参数(功能还是单一),通过传递对象的形式

在这里插入图片描述

        // 封装函数
        // function move(element, type, target) {
        function move(element, object) {
            for(let key in object){
                let type = key;
                let target = object[key];

                if(type === 'opacity') target *= 100;

                let timer = setInterval(function(){
                    // 获取当前位置的值  兼容透明度
                    let count = type == 'opacity' ? window.getComputedStyle(element)[type]*100 : parseInt(window.getComputedStyle(element)[type]);
                        
                    // 计算要移动的距离(目标 - 当前的值) / 10;
                    let des = (target - count) / 10;
                    // 大于0向上取整 小于0向下取整
                    des = des > 0 ? Math.ceil(des) : Math.floor(des);

                    // 判断是否需要继续移动
                    if(des === count){
                        // 此时说明移动到了 可以结束定时器了
                        clearInterval(timer);
                    }else{
                        // 此时说明还没有移动到, 需要继续移动
                        // 兼容透明度
                        if(type === 'opacity'){

                            element.style[type] = (count + des) / 100;
                        }else{
                            
                            element.style[type] = count + des + 'px';
                        }
                    }
                })
            }
        }

        // 获取标签对象
        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, {
                opacity:0.3,
            })
        })

        oDiv2.addEventListener('click', function () {
            move(this,{
                left:200,
                opacity:1,
                width: 200
            })
        })

在这里插入图片描述

六、运动函数真正结束

  1. 问题:没有办法完全捕获到运动函数的真正结束
  2. 原因:对象的每个属性,都会开启一个循环,每一个循环都会开启一个定时器,每个运动结束,就会结束一个定时器
  3. 解决:使用一个变最去记录,初始值可以给0,每次开启定时器的时候让变量自增,然后每次结束定时器的时候让变量自减

在这里插入图片描述

// 定义变量 存储数据
let num = 0;

// 封装函数
// function move(element, type, target) {
function move(element, object, fn = () => {}) {
    for(let key in object){
        let type = key;
        let target = object[key];

        if(type === 'opacity') target *= 100;

        // 开启定时器 让变量自增 记录一下开启运动
        num++;

        let timer = setInterval(function(){
            // 获取当前位置的值  兼容透明度
            let count = type == 'opacity' ? window.getComputedStyle(element)[type]*100 : parseInt(window.getComputedStyle(element)[type]);
                
            // 计算要移动的距离(目标 - 当前的值) / 10;
            let des = (target - count) / 10;
            // 大于0向上取整 小于0向下取整
            des = des > 0 ? Math.ceil(des) : Math.floor(des);

            // 判断是否需要继续移动
            if(target === count){
                // 定时器结束 变量--
                num--;
                if(num === 0){
                    console.log('函数结束了');
                }

                // 此时说明移动到了 可以结束定时器了
                clearInterval(timer);
            }else{
                // 此时说明还没有移动到, 需要继续移动
                // 兼容透明度
                if(type === 'opacity'){

                    element.style[type] = (count + des) / 100;
                }else{
                    
                    element.style[type] = count + des + 'px';
                }
            }
        })
    }
}


// 获取标签对象
const oDiv1 = document.querySelector('.box1');
const oDiv2 = document.querySelector('.box2');

// 调用函数
oDiv1.addEventListener('click', function () {
    move(oDiv1, {
        opacity:0.3,
    })
})

oDiv2.addEventListener('click', function () {
    move(this,{
        left:200,
        width: 200,
        opacity: 1
    })
})

在这里插入图片描述

七、回调函数

  1. 问题:我们现在想在运动函数结束之后做某些事,但是目前没法做到
  2. 原因:运动函数是异步的,所以会先执行同步代码
  3. 解决:在运动函数开始的时候,给他一个“锦囊”然后合诉运动函数,在运动完了的时候,才能打开“锦囊”

回调函数

  • 回调函数(本质上就是一个函数),将函数A以实参的形式传递给函数B,然后函数B在函数内部以形参的方式调用函数A,此时函数A可以称为函数B的回调函数
  • 回调函数一般用于异步代码的封装
        // 定义变量 存储数据
        let num = 0;

        // 封装函数
        // function move(element, type, target) {
        function move(element, object, fn = () => {}) {
            for(let key in object){
                let type = key;
                let target = object[key];

                if(type === 'opacity') target *= 100;

                // 开启定时器 让变量自增 记录一下开启运动
                num++;

                let timer = setInterval(function(){
                    // 获取当前位置的值  兼容透明度
                    let count = type == 'opacity' ? window.getComputedStyle(element)[type]*100 : parseInt(window.getComputedStyle(element)[type]);
                        
                    // 计算要移动的距离(目标 - 当前的值) / 10;
                    let des = (target - count) / 10;
                    // 大于0向上取整 小于0向下取整
                    des = des > 0 ? Math.ceil(des) : Math.floor(des);

                    // 判断是否需要继续移动
                    if(target === count){
                        // 定时器结束 变量--
                        num--;
                        if(num === 0){
                            // 调用回调函数
                            fn()
                            console.log(num)
                        }

                        // 此时说明移动到了 可以结束定时器了
                        clearInterval(timer);
                    }else{
                        // 此时说明还没有移动到, 需要继续移动
                        // 兼容透明度
                        if(type === 'opacity'){

                            element.style[type] = (count + des) / 100;
                        }else{
                            
                            element.style[type] = count + des + 'px';
                        }
                    }
                })
            }
        }


        // 获取标签对象
        const oDiv1 = document.querySelector('.box1');
        const oDiv2 = document.querySelector('.box2');

        // 调用函数
        oDiv1.addEventListener('click', function () {
            move(oDiv1, {
                opacity:0.3,
            })
        })

        oDiv2.addEventListener('click', function () {
            move(this,{
                left:200,
                width: 200,
                opacity: 1
            },() =>{
                console.log('运动结束,背景色改为royalblue');
                this.style.backgroundColor = 'royalblue';
            })
        })

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/45839.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

回溯法(Java)

回溯法&#xff08;Java&#xff09; 文章目录回溯法&#xff08;Java&#xff09;1、引言2、回溯法2.1 定义2.2 使用场合2.3 基本做法2.4 具体做法2.5 常见例子3、比较4、 问题的解空间4.1 介绍4.2 解空间&#xff08;Solution Space&#xff09;4.3 举例5、基本思想5.1 基本步…

Starday跨境电商平台靠“三快”取胜

入驻快、支付快、物流快 在这个瞬息万变的互联网世界&#xff0c;追求“快”已经成为各行各业的共识&#xff0c;而对于一个因互联网发展而诞生的新兴行业——跨境电商行业&#xff0c;“快”就是跨境电商行业的第一生产力&#xff0c;要想在众多的跨境电商行业中成功出圈&…

【allegro 17.4软件操作保姆级教程六】布线操作基础之一

目录 1.1走线和修线 1.2 Copy操作 1.3 change操作 1.4 删除操作 1.5 Z-copy操作 1.6 Sub-drawing操作 1.1走线和修线 这两个操作是布线时用的最多最基础的操作。如下图&#xff0c;左边是走线命令&#xff08;add connect&#xff09;&#xff0c;右边是修线命令&#x…

外卖项目(项目优化3)12---前后端分离开发

目录 问题描述&#xff1a;184 一、前后端分离开发 185 1.1介绍 185 1.2开发流程 1.3前端技术栈 二、YAPI 186 2.1介绍 2.2使用方式 三、Swagger 187 3.1介绍 3.2使用方式&#xff08;步骤&#xff09; 3.3Swagger---常用注解 188 四、项目部署 189 4.1部署架构…

虹科分享 | 网络流量监控 | 使用 ntopng 收件人和端点进行灵活的警报处理

在之前&#xff0c;ntopng引擎对所有警报的配置是单一的&#xff1a;进入偏好页面并指定警报的发送地点。但这是不理想的&#xff0c;原因有很多&#xff1a;包括不可能在不同的渠道向不同的收件人发送警报&#xff0c;或有选择地决定何时发送警报。 出于这个原因&#xff0c;…

【教材】20022/11/28[指针] 指针数组

一个数组,若其元素均为指针类型数据,称为指针数组,也就是说,指针数组中的每一个元素都存放一个地址,相当于一个指针变量。下面定义一个指针数组:int *p[4] 注意不要写成int &#xff08;*p&#xff09;[4]. 可以分别定义一些字符串,然后用指针数组中的元素分别指向各字符串,在n…

二手闲置物品交易数据快照

近年来&#xff0c;中国社会消费品零售总额不断增长&#xff0c;2019 年1-4 月,消费品零售总额达到128375.8 亿元&#xff0c;同比增长8%。消费者购买力的增强和电商行业的发展&#xff0c;给购买行为提供便利条件&#xff0c;消费者冲动消费后的闲置产品&#xff0c;给二手交易…

《前端》JavaScript总结

文章目录js的使用方法变量与运算符let 与 const变量类型运算符输入与输出输入输出格式化字符串判断语句循环语句for循环while循环do...while循环对象数组访问数组中的元素数组常用属性和函数函数类定义继承静态方法静态变量事件鼠标键盘表单窗口js的使用方法 **使用方式&#…

网络安全工程师必备证书有哪些?

网络环境之间的竞争&#xff0c;归根到底优秀人才之间的竞争。 在2022年网络安全周上&#xff0c;《网络安全人才实战能力白皮书》正式公布。资料显示&#xff0c;到2027年&#xff0c;我国网络安全人员缺口将达327万&#xff0c;而高校人才培养经营规模仅是3万/年。 那样&am…

上半年亏损之下,卫龙第三次冲刺港股IPO

据港交所文件显示&#xff0c;今年6月27日卫龙美味通过港交所上市聆听&#xff0c;11月24日&#xff0c;卫龙更新了聆听后资料集。若此次上市成功&#xff0c;卫龙将成为港股乃至国内辣条第一股。 此前&#xff0c;卫龙已经两度申请了赴港IPO&#xff0c;但都功败垂成&#xff…

看看咱是如何用MATLAB白嫖遥遥领先于同行的神仙级翻译工具 — DeepL

伙伴们不用惊讶&#xff0c;标题仅仅是借用余大嘴的专用修饰语“遥遥领先于同行”而已&#xff0c;但讲DeepL翻译器遥遥领先于同行也不为过&#xff0c;下图是官方给出的采用盲测的方式与其他同类产品的对比图&#xff0c;这应该不是吹牛X&#xff1a; 如此优秀的翻译神器&…

免改造密码方案入选工信部“首届全国商用密码应用优秀案例”

2022年8月18日&#xff0c;“首届全国商用密码应用优秀案例”评选结果重磅揭晓&#xff0c;炼石网络与陕西移动联合打造的“面向重要数据与个人信息保护的商用密码解决方案”&#xff0c;凭借创新性及技术优势&#xff0c;从102个案例中脱颖而出、成功入选&#xff0c;并被收录…

yolov4训练数据: cuda和cudnn的安装

近期再搞openvinoYolov4目标检测&#xff0c;记录一下cuda和cudnn的安装笔记。 mirrors / alexeyab / darknet GitCode 1.cuda的安装 cuDNN Archive | NVIDIA Developer wget https://developer.download.nvidia.com/compute/cuda/10.2/Prod/local_installers/cuda_10.2.89_…

【SVM时序预测】基于matlab鲸鱼算法优化支持向量机SVM时序数据预测【含Matlab源码 2250期】

⛄一、鲸鱼算法优化支持向量机SVM 1 鲸鱼优化算法 WOA是由Mirjalili和Lewis在2016年提出的一种较为新颖的元启发式群体智能优化算法&#xff0c;该算法模仿座头鲸的“螺旋气泡网”捕食策略&#xff0c;如图1所示。 图1 座头鲸“螺旋起泡网”捕食策略 WOA算法寻优步骤如下。 步…

详解企业财务数字化转型路径|推荐收藏

许多企业在推动各大业务部门进行数字化转型时&#xff0c;往往会忽略财务部门。然而&#xff0c;作为掌握公司核心资源与数据和推动企业信息化建设的部门&#xff0c;财务部门也应成为企业数字化转型的重要突破口。 财务数字化转型是运用信息技术等手段对财务数据进行统计、记录…

【Android App】三维投影OpenGL ES的讲解及着色器实现(附源码和演示 超详细)

需要源码请点赞关注收藏后评论区留言私信~~~ 一、OpenGL ES简介 虽然OpenGL的三维制图功能非常强大&#xff0c;但是它主要为计算机设计的&#xff0c;对于嵌入式设备和移动端设备来说显得比较臃肿&#xff0c;所以业界又设计了专供嵌入式设备的OpenGL ES 它相当于OpenGL的精简…

GPS定位原理

GPS卫星&#xff1a; 卫星定位系统是一种使用卫星对某物进行准确定位的技术&#xff0c;它从最初的定位精度低、不能实时定位、难以提供及时的导航服务&#xff0c;发展到现如今的高精度GPS全球定位系统&#xff0c;实现了在任意时刻、地球上任意一点都可以同时观测到4颗卫星&a…

OS_虚拟内存@请求分页系统@驻留集@内存分配策略

文章目录OS_虚拟内存请求分页系统驻留集内存分配策略请求分页系统页表机制缺页中断机构地址变换机构页框分配驻留集分配策略固定分配可变分配置换策略局部置换全局置换策略组合固定分配局部置换可变分配全局置换可变分配局部置换&#x1f388;OS_虚拟内存请求分页系统驻留集内存…

docker中安装并启动rabbitMQ

docker中安装并启动rabbitMQ1、安装rabbitMQ1.1、拉取镜像1.2、启动容器实例1.3、开启web界面管理插件1.4、浏览器访问 rabbitMQ2、解决Docker部署rabbitmq遇到的如下两个问题&#xff1a;2.1、访问交换机时报错&#xff0c;Management API returned status code 5002.2、访问c…

003. 电话号码的字母组合——回溯算法

1.题目链接&#xff1a; 17. 电话号码的字母组合 2.解题思路&#xff1a; 2.1.题目要求&#xff1a; 给定一个仅包含数字 2-9 的字符串 digits &#xff0c;返回所有它能表示的字母组合。 数字和字母的关系&#xff1a; 例子&#xff1a; 输入&#xff1a;"23" …