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

执行结果 :

相关推荐
HIT_Weston1 小时前
59、【Ubuntu】【Gitlab】拉出内网 Web 服务:Gitlab 配置审视(三)
前端·ubuntu·gitlab
syt_10131 小时前
grid布局之-子项放置2
前端·javascript·css
fruge1 小时前
Vue3 响应式原理深度解析:Proxy 实现与依赖收集逻辑
前端
by__csdn1 小时前
javascript 性能优化实战:异步和延迟加载
开发语言·前端·javascript·vue.js·性能优化·typescript·ecmascript
by__csdn1 小时前
JavaScript性能优化实战:减少DOM操作全方位攻略
前端·javascript·vue.js·react.js·性能优化·typescript
xiaoxue..1 小时前
从 “手动搬砖“ 到 “自动施法“:界面开发的三次 “渡劫“ 升级记
前端·前端框架·vue
哆啦A梦15881 小时前
商城后台管理系统 05 商品列表-静态布局
javascript·vue.js·elementui
Monly211 小时前
Vue:使用v-if v-else加载两个el-table 在切换时,会出现数据在家混乱 数据加载不全的情况
前端·javascript·vue.js
南知意-1 小时前
一个基于 Vue、Datav、Echart 框架开源免费的数据大屏可视化系统
前端·javascript·vue.js·开源软件·大屏项目