【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>

执行结果 :

相关推荐
一个懒人懒人7 小时前
Promise async/await与fetch的概念
前端·javascript·html
Mintopia7 小时前
Web 安全与反编译源码下的权限设计:构筑前后端一致的防护体系
前端·安全
输出输入7 小时前
前端核心技术
开发语言·前端
Mintopia7 小时前
Web 安全与反编译源码下的权限设计:构建前后端一体的信任防线
前端·安全·编译原理
林深现海7 小时前
Jetson Orin nano/nx刷机后无法打开chrome/firefox浏览器
前端·chrome·firefox
黄诂多7 小时前
APP原生与H5互调Bridge技术原理及基础使用
前端
前端市界8 小时前
用 React 手搓一个 3D 翻页书籍组件,呼吸海浪式翻页,交互体验带感!
前端·架构·github
文艺理科生8 小时前
Nginx 路径映射深度解析:从本地开发到生产交付的底层哲学
前端·后端·架构
千寻girling8 小时前
主管:”人家 Node 框架都用 Nest.js 了 , 你怎么还在用 Express ?“
前端·后端·面试
C澒8 小时前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构