封装动画函数

文章目录

    • 需求分析
    • 确定参数
    • 确定属性值
    • 具体实现
    • 简单扩展

需求分析

  1. 在 css 中,如果要给一个元素设置动画,就要改变一个css属性,也是一个值到另外一个值的变化,
  2. 但是放入到我们这里的动画函数里面,我是不知道是具体要用到那个元素上的,所以只能是计算一个数据值到另一个数据值的变化
  3. 什么变化呢?比如在多少时间内,1-100,变化的频率等等,所以我们只要能实现这些就好了

确定参数

  1. 一段时间内,一个值到另外一个值,首先就要知道这个一段时间有多长,还需要知道在这个值变化的过程中,例如 1-10,5s的时间,变化的步进值,比如每次前进0.1还是0.5,所以还需要一个间隔时间。比如500ms变化一次,那么每次的步进的就是10/(10000ms/500ms),每次前进 0.5,前进 20 次
  2. 基于此,我们就确定了四个参数:起始值、结束值、总时间、间隔时间
  3. 那么这个是不是完成了呢?不然,我每次改变的值,总需要使用吧,这个使用方式,是多种多样的,只能交给使用者来决定,而适合这种灵活的场景,只有是函数了,所以还需要一个参数,回调函数,这个回调函数的执行时机是每次间隔时间后调用一次,调用多少次,取决于传递的参数

确定属性值

  1. 我们还需要那些属性呢?

  2. 首先就是计时器的id:timer;然后运动的总次数:count;当前的运动次数:curCount;当前值:curValue

  3. 所以我们现在可以写出一个大概的函数模型,如下:

    function animationFunc({ begin, end, interval = 16, total = 3000, callback }) {let timer = null // 接收定时器IDlet count = Math.ceil(total / interval) // 运动次数【向上取整】let step = Math.abs((end - begin)) / count // 每次运动的步长let current = begin // 当前的位置let currentCount = 0 // 当前运动次数timer = setInterval(() => {// 如果存在回调函数就调用-并传递当前值callback && callback(current)}, interval)
    }
    

具体实现

  1. 其实到现在,我们的这个插件已经实现的差不多了,只是缺少一些值的计算和停止条件

  2. 每次执行后次数+1,当前值 = 当前值 + 每次运动的步长,如果当前次数大于或者等于总次数,就停止执行,如下:

    function animationFunc({ begin, end, interval = 16, total = 3000, callback }) {let timer = nulllet count = Math.ceil(total / interval)let step = Math.abs(end - begin) / countlet curValue = beginlet currentCount = 0timer = setInterval(() => {// 改变当前值curValue += step// 次数+1currentCount++// 如果当前次数大于或者等于总次数就停止执行if (currentCount >= count) {// 动画结束callback && callback(curValue)clearInterval(timer)timer = nullreturn}callback && callback(curValue)}, interval)
    }
    
  3. 那我们具体使用看一下,html 中写了一个使用绝对定位固定的 div,如下:

    <!DOCTYPE html>
    <html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><style>.box {position: absolute;left: 0;top: 20px;background-color: skyblue;width: 100px;height: 100px;}</style>
    </head><body><div class="box"></div><script src="./index.js"></script>
    </body></html>
    
  4. 看看使用代码,如下:

    const box = document.querySelector('.box')// 动画函数
    function animationFunc({ begin, end, interval = 16, total = 3000, callback }) {let timer = nulllet count = Math.ceil(total / interval)let step = Math.abs(end - begin) / countlet curValue = beginlet currentCount = 0timer = setInterval(() => {curValue += stepcurrentCount++if (currentCount >= count) {callback && callback(curValue)clearInterval(timer)timer = nullreturn}callback && callback(curValue)}, interval)
    }box.onclick = function () {animationFunc({begin: 0,end: 500,callback: curValue => {box.style.left = curValue + 'px'}})
    }
    
  5. 执行效果如图:

    在这里插入图片描述

  6. 当然经过 gif 的转换和录屏本身的原因,会存在不小的抖动

简单扩展

  1. 上述我们已经实现了这个动画的函数,而且由于具体实现的业务不为动画函数本身决定,大大增加了灵活程度,但是业务总是千奇百怪的,比如我可能是希望能在动画执行开始和完成的时机调用一个方法,告诉我动画函数执行完成了,此时我们可以多加两个参数 onBegin、onFinish,同时为了具备的更加语义化 callback 改为 onChange,如下:

    const box = document.querySelector('.box')// 动画函数
    function animationFunc({ begin, end, interval = 16, total = 3000, onChange, onBegin, onFinish }) {// 执行的时候调用一次 onBeginonBegin && onBegin()let timer = nulllet count = Math.ceil(total / interval)let step = Math.abs(end - begin) / countlet curValue = beginlet currentCount = 0timer = setInterval(() => {curValue += stepcurrentCount++if (currentCount >= count) {// 执行完成后调用 onFinishonFinish && onFinish()onChange && onChange(curValue)clearInterval(timer)timer = nullreturn}onChange && onChange(curValue)}, interval)
    }box.onclick = function () {animationFunc({begin: 0,end: 500,onChange: curValue => {box.style.left = curValue + 'px'},onBegin: () => {box.innerHTML = '开始执行动画'},onFinish: () => {box.innerHTML = '动画执行完成'}})
    }
    
  2. 效果如图:

    在这里插入图片描述

  3. 至于具体需要利用这两个时机完成什么,或者做点什么,就看各自的业务需求了,还可以根据你自己的需求作出更多扩展,比如传递多个起始值可以执行多组动画

  4. 当然,考虑严谨性,可以考虑多写一些参数的类型判断或者当前的值如果大于了结束值,就赋值为结束值,如下:

    function isFunction(value) {// 为空表示未使用,则默认返回 trueif (value === null || value === undefined) return truereturn typeof value === 'function'
    }// 动画函数
    function animationFunc({ begin, end, interval = 16, total = 3000, onChange, onBegin, onFinish }) {if (!isFunction(onBegin)) {throw new Error('onBegin 必须是函数')}if (!isFunction(onFinish)) {throw new Error('onFinish 必须是函数')}if (!isFunction(onChange)) {throw new Error('onChange 必须是函数')}if (begin === undefined || begin === null) {throw new Error('begin 必须有值')}if (end === undefined || end === null) {throw new Error('end 必须有值')}onBegin && onBegin()let timer = nulllet count = Math.ceil(total / interval)let step = Math.abs(end - begin) / countlet curValue = beginlet currentCount = 0timer = setInterval(() => {curValue += stepcurrentCount++if (curValue > end) curValue = endif (currentCount >= count) {onFinish && onFinish()onChange && onChange(curValue)clearInterval(timer)timer = nullreturn}onChange && onChange(curValue)}, interval)
    }
    

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

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

相关文章

STK 特定问题建模(五)频谱分析(第二部分)

文章目录 简介三、链路分析3.1 星地链路干扰分析3.2 频谱分析 简介 本篇对卫星通信中的频谱利用率、潜在干扰对频谱的影响进行分析&#xff0c;以LEO卫星信号对GEO通信链路影响为例&#xff0c;分析星地链路频谱。 建模将从以下几个部分开展&#xff1a; 1、GEO星地通信收发机…

Java接口的解析

在 Java 中&#xff0c;接口&#xff08;Interface&#xff09;是一种抽象类型&#xff0c;用于定义一组相关方法的契约。接口只包含方法的签名&#xff0c;而没有方法的实现。实现接口的类必须提供接口中定义的方法的具体实现。 以下是对 Java 接口的解析&#xff1a; 这只是…

使用Scikit Learn 进行识别手写数字

使用Scikit Learn 进行识别手写数字 作者&#xff1a;i阿极 作者简介&#xff1a;数据分析领域优质创作者、多项比赛获奖者&#xff1a;博主个人首页 &#x1f60a;&#x1f60a;&#x1f60a;如果觉得文章不错或能帮助到你学习&#xff0c;可以点赞&#x1f44d;收藏&#x1f…

MySql -数据库进阶

一、约束 1.外键约束 外键约束概念 让表和表之间产生关系&#xff0c;从而保证数据的准确性&#xff01; 建表时添加外键约束 为什么要有外键约束 -- 创建db2数据库 CREATE DATABASE db2; -- 使用db2数据库 USE db2;-- 创建user用户表 CREATE TABLE USER(id INT PRIMARY KEY …

2024-01-09 Android.mk 根据c文件名插入特定的宏定义,我这里用于定义log LOG_TAG 标签

一、在Android的构建系统中&#xff0c;使用Android.mk构建脚本可以根据特定需求来定义宏。如果你想根据C文件的名称来插入特定的宏定义&#xff0c;可以使用条件语句检查文件名&#xff0c;并相应地设置宏。 在Android的构建系统中&#xff0c;使用Android.mk构建脚本可以根据…

【MySQL】表设计与范式设计

文章目录 一、数据库表设计一对一一对多多对多 二、范式设计第一范式第二范式第三范式BC范式第四范式 一、数据库表设计 一对一 举个例子&#xff0c;比如这里有两张表&#xff0c;用户User表 和 身份信息Info表。 因为一个用户只能有一个身份信息&#xff0c;所以User表和In…

jmeter+ant+Jenkins集成

一、 环境准备 1、Jenkins下载&#xff1a;https://jenkins.io/zh/download/ 2、 Jenkins安装&#xff1a;解压下载的压缩包&#xff0c;直接点击msi文件安装即可 4、 Jenkins登录用户设置&#xff1a;装&#xff1a; 浏览器地址栏中输入&#xff1a;http://localhost:8080/…

益生菌抗癌?补充这种益生菌,抑制肝癌,还改善肠道健康

撰文 | 宋文法 肠道菌群&#xff0c;是人体不可分割的组成部分&#xff0c;生活在我们肠道内的数万亿细菌对健康起着重要作用&#xff0c;它们影响着人的新陈代谢、消化能力、抵御感染、控制人体对药物的反应&#xff0c;甚至还能预防某些癌症。 非酒精性脂肪肝病&#xff0c;是…

【实用技巧】Windows 电脑向iPhone或iPad传输视频方法1:无线传输

一、内容简介 本文介绍如何使用 Windows 电脑向 iPhone 或 iPad 传输视频&#xff0c;以 iPhone 为例&#xff0c;iPad的操作方法类似&#xff0c;本文不作赘述。 二、所需原材料 Windows 电脑&#xff08;桌面或其它文件夹中存有要导入的视频&#xff09;、iPhone 14。 待…

Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域并放大,Kotlin(3)

Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域并放大&#xff0c;Kotlin&#xff08;3&#xff09; 在文章2 Android Canvas图层saveLayer剪切clipPath原图addCircle绘制对应圆形区域&#xff0c;Kotlin&#xff08;2&#xff09;-CSDN博客 的基础上&…

Unity中Shader序列帧动画(总结篇)

文章目录 前言一、半透明混合自定义调整1、属性面板2、SubShader中3、在片元着色器(可选)3、根据纹理情况自己调节 二、适配Build In Render Pipeline三、最终代码 前言 在前几篇文章中&#xff0c;我们依次解决了实现Shader序列帧动画所遇到的问题。 Unity中Shader序列图动画…

二叉树及其实现

二叉树 一.树的概念及结构1.1树的概念1.2相关概念 2.二叉树的概念及结构2.1 概念2.2 特殊的二叉树 3.二叉树的遍历3.1 前序、中序以及后序遍历3.2 层序遍历3.3 判断二叉树是否是完全二叉树3.4 二叉树的高度3.5 二叉树的叶子节点个数3.6 二叉树的第k层的节点个数3.7 二叉树销毁3…

苹果可充电键盘背光系统专利曝光:延长MacBook Air / Pro续航

根据美国商标和专利局&#xff08;USPTO&#xff09;近日公示的清单&#xff0c;苹果公司近日获得了一项关于电子设备键盘的相关专利。 苹果公司在专利中表示&#xff0c;为了在低光环境下&#xff0c;能够提高用户敲击键盘的输入体验&#xff0c;通常键盘会提供背光。 传统键…

深度学习笔记(二)——Tensorflow环境的安装

本篇文章只做基本的流程概述&#xff0c;不阐述具体每个软件的详细安装流程&#xff0c;具体的流程网上教程已经非常丰富。主要是给出完整的安装流程&#xff0c;以供参考 环境很重要 一个好的算法环境往往能够帮助开发者事半功倍&#xff0c;入门学习的时候往往搭建好环境就已…

关于Vue前端接口对接的思考

关于Vue前端接口对接的思考 目录概述需求&#xff1a; 设计思路实现思路分析1.vue 组件分类和获取数值的方式2.http 通信方式 分类 如何对接3.vue 组件分类和赋值方式&#xff0c; 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your p…

基于uniapp封装的table组件

数据格式 tableData: [{elcInfo: [{tableData:[1,293021.1,293021.1,293021.1,293021.1,]}]},{elcInfo: [{tableData:[1,293021.1,293021.1,293021.1,293021.1,]}]},{elcInfo: [{tableData:[1,293021.1,293021.1,293021.1,293021.1,]}]},/* {title: "2",elcInfo: [{…

知识图谱gds使用记录

安装 从下载站下载对应的包到plugin目录下&#xff0c;修改配置文件/etc/neo4j/neo4j.conf&#xff0c;末尾加入gds.*&#xff0c;重新启动 在浏览器输入CALL gds.list()命令进行测试 建立图映射 为了使用图算法&#xff0c;需要先将图数据库的内容映射为一个新图 如果是全…

freesurfer-reconall后批量提取TIV(颅内总体积)

#提取TIV #singleline=$(grep Estimated Total Intracranial Volume /usr/local/freesurfer/subjects/bect-3d+bold-wangjingchen-4.9y-2/stats/aseg.sta

学习笔记——C++运算符之算术运算符

C中运算符包含诸多种类&#xff0c;其中有&#xff1a;算术运算符&#xff0c;赋值运算符&#xff0c;比较运算符和逻辑运算符 每一种运算符及其作用如下表所示&#xff1a; 一&#xff0c;算术运算符1&#xff0c;加减乘除 其中&#xff0c;“”&#xff0c;“-”运算符既可…

基于ssm智慧社区停车管理系统设计与实现【附源码】

基于ssm智慧社区停车管理系统设计与实现 &#x1f345; 作者主页 央顺技术团队 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; &#x1f345; 文末获取源码联系方式 &#x1f4dd; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&am…