【Web APIs】JavaScript 动画 ② ( 缓动动画 | 步长计算取整 )

文章目录

一、缓动动画


1、缓动动画原理

匀速动画 : 之前的博客 【Web APIs】JavaScript 动画 ① ( setInterval 实现动画原理 | 动画函数封装 | 元素自定义属性接收定时器标识 ) 中 实现的动画 是 匀速动画 , 为 obj 元素设置的 定时器 每次 向前移动 1 像素 ;

javascript 复制代码
obj.style.left = obj.offsetLeft + 1 + 'px';

该动画的 移动步长 是 1 像素 , 也就是 每隔 30 ms 向前移动 1 像素 ;

" 匀速动画 " 的 原理是 " 元素盒子位置 + 固定值步长 " ;

与 匀速动画 相对的是 " 缓动动画 " , 缓动动画 的 原理是 " 元素盒子位置 + 不固定值步长 " ;

不固定步长值计算 , 需要 将 计算过程 写到 定时器 中 , target 是 动画目的地位置 , obj.offsetLeft 是 当前的元素位置 , 移动的 步长是 " 动画目的地位置 - 当前的元素位置 " 的 十分之一 长度 ;

每次计算出来的 步长 是不同的 , 每一次计算出来的步长 , 都比前一次要短 ;

javascript 复制代码
// 步长值计算 : 将 计算过程 写到定时器 函数里面
var step = (target - obj.offsetLeft) / 10;

每隔 30 ms 执行定时器时 , 修改 元素的 left 值 , 每次增加 计算出的 step 步长值 , 实现缓动动画效果 ;

javascript 复制代码
                // 操作对象 : 从具体的 div.style.left 改为形参传入的 obj.style.left 参数
                // 每次定时器执行时 , 修改元素的 left 值 , 实现动画效果
                // 每次增加 计算出的 step 步长值 , 实现缓动效果
                obj.style.left = obj.offsetLeft + step + 'px';

2、代码示例

代码示例 :

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>缓动动画</title>
    <style>
        div {
            /* 绝对定位 元素 优先以 最近的 已定位 祖先元素 为基准 , 无则以 视口 ( body 元素 ) 为基准 ; */
            position: absolute;
            /* 该属性就是实现动画时 , 实时改变的属性 */
            /* 初始左侧偏移量 : 动画起始位置 , 后续JS会实时修改该值实现移动 */
            left: 0;
            /* 元素的 大小 和 样式 */
            /* 元素宽度 : 固定尺寸 , 仅做样式展示 */
            width: 100px;
            /* 元素高度 : 固定尺寸 , 仅做样式展示 */
            height: 100px;
            /* 背景颜色 : 设置粉色 , 区分元素视觉效果 */
            background-color: pink;
        }
    </style>
</head>

<body>
    <!-- 动画在载体元素 1 -->
    <div></div>
    <script>
        // 匀速动画 : 元素盒子位置 + 固定值步长
        // 缓动动画 : 元素盒子位置 + 不固定值步长

        // 形参 obj : 接收要做动画的 DOM 元素 ( 如 : div、span ) 
        // 形参 target : 接收动画的终止位置 ( 如 : 300、200 ) 
        function animate(obj, target) {

            // 定时器标识 : 用于清除定时器 , 避免多个定时器同时运行
            obj.timer = setInterval(function() {
                // 不固定步长值计算 : 将 计算过程 写到定时器 函数里面
                var step = (target - obj.offsetLeft) / 10;

                // 步长值取整 : 向上取整 / 向下取整 
                // 步长值为正数 , 向右运动 , 必须向上取整 , 否则会出现动画向左回退的现象
                // 步长值为负数 , 向左运动 , 必须向下取整 , 否则会出现动画向右回退的现象
                //step = step > 0 ? Math.ceil(step) : Math.floor(step);

                // 终止条件:从固定 400px 改为动态的 target 参数
                if (obj.offsetLeft >= target) {
                    clearInterval(obj.timer);
                }
                // 操作对象 : 从具体的 div.style.left 改为形参传入的 obj.style.left 参数
                // 每次定时器执行时 , 修改元素的 left 值 , 实现动画效果
                // 每次增加 计算出的 step 步长值 , 实现缓动效果
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 30);
        }

        // 获取要做动画的 DOM 元素
        var div = document.querySelector('div');

        // 调用动画函数, 为两个 DOM 元素分别设置动画
        animate(div, 300);

        // 调试 : 打印定时器标识 , 便于调试
        console.log(div.timer);
    </script>
</body>

</html>

执行结果 :

二、步长计算取整


1、步长计算取整

设置缓动动画 移动 300 像素后 , 最终 div 元素停留在的位置 对应的 left 属性值是 296.4px ;

在页面中 , 如果出现最终位置不是整数 , 导致 多个元素无法 对齐 的情况 ;

步长取整 , 需要考虑 步长值 是 正数 和 负数 的情况 :

  • 步长值为正数 , 向右运动 , 必须向上取整 , 否则会出现动画向左回退的现象 ;
  • 步长值为负数 , 向左运动 , 必须向下取整 , 否则会出现动画向右回退的现象 ;
javascript 复制代码
                // 步长值取整 : 向上取整 / 向下取整 
                // 步长值为正数 , 向右运动 , 必须向上取整 , 否则会出现动画向左回退的现象
                // 步长值为负数 , 向左运动 , 必须向下取整 , 否则会出现动画向右回退的现象
                step = step > 0 ? Math.ceil(step) : Math.floor(step);

2、代码示例

代码示例 :

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>缓动动画</title>
    <style>
        div {
            /* 绝对定位 元素 优先以 最近的 已定位 祖先元素 为基准 , 无则以 视口 ( body 元素 ) 为基准 ; */
            position: absolute;
            /* 该属性就是实现动画时 , 实时改变的属性 */
            /* 初始左侧偏移量 : 动画起始位置 , 后续JS会实时修改该值实现移动 */
            left: 0;
            /* 元素的 大小 和 样式 */
            /* 元素宽度 : 固定尺寸 , 仅做样式展示 */
            width: 100px;
            /* 元素高度 : 固定尺寸 , 仅做样式展示 */
            height: 100px;
            /* 背景颜色 : 设置粉色 , 区分元素视觉效果 */
            background-color: pink;
        }
    </style>
</head>

<body>
    <!-- 动画在载体元素 1 -->
    <div></div>
    <script>
        // 匀速动画 : 元素盒子位置 + 固定值步长
        // 缓动动画 : 元素盒子位置 + 不固定值步长

        // 形参 obj : 接收要做动画的 DOM 元素 ( 如 : div、span ) 
        // 形参 target : 接收动画的终止位置 ( 如 : 300、200 ) 
        function animate(obj, target) {

            // 定时器标识 : 用于清除定时器 , 避免多个定时器同时运行
            obj.timer = setInterval(function() {
                // 不固定步长值计算 : 将 计算过程 写到定时器 函数里面
                var step = (target - obj.offsetLeft) / 10;

                // 步长值取整 : 向上取整 / 向下取整 
                // 步长值为正数 , 向右运动 , 必须向上取整 , 否则会出现动画向左回退的现象
                // 步长值为负数 , 向左运动 , 必须向下取整 , 否则会出现动画向右回退的现象
                step = step > 0 ? Math.ceil(step) : Math.floor(step);

                // 终止条件:从固定 400px 改为动态的 target 参数
                if (obj.offsetLeft >= target) {
                    clearInterval(obj.timer);
                }
                // 操作对象 : 从具体的 div.style.left 改为形参传入的 obj.style.left 参数
                // 每次定时器执行时 , 修改元素的 left 值 , 实现动画效果
                // 每次增加 计算出的 step 步长值 , 实现缓动效果
                obj.style.left = obj.offsetLeft + step + 'px';
            }, 30);
        }

        // 获取要做动画的 DOM 元素
        var div = document.querySelector('div');

        // 调用动画函数, 为两个 DOM 元素分别设置动画
        animate(div, 300);

        // 调试 : 打印定时器标识 , 便于调试
        console.log(div.timer);
    </script>
</body>

</html>

执行结果 :

相关推荐
cz追天之路18 小时前
华为机考--- 字符串最后一个单词的长度
javascript·css·华为·less
Light6018 小时前
CSS逻辑革命:原生if()函数如何重塑我们的样式编写思维
前端·css·响应式设计·组件化开发·css if函数·声明式ui·现代css
蜡笔小嘟18 小时前
宝塔安装dify,更新最新版本--代码版
前端·ai编程·dify
ModyQyW19 小时前
HBuilderX 4.87 无法正常读取 macOS 环境配置的解决方案
前端·uni-app
bitbitDown19 小时前
我的2025年终总结
前端
五颜六色的黑19 小时前
vue3+elementPlus实现循环列表内容超出时展开收起功能
前端·javascript·vue.js
wscats20 小时前
Markdown 编辑器技术调研
前端·人工智能·markdown
EnoYao20 小时前
Markdown 编辑器技术调研
前端·javascript·人工智能
JIngJaneIL21 小时前
基于java+ vue医院管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
JIngJaneIL21 小时前
基于java + vue校园跑腿便利平台系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot