缓动动画典藏版
缓动动画思路
/*
1.缓动动画核心思路 : 由快到慢
本次移动距离 = (目标位置 - 当前位置)/10
2.缓动动画特点
(1)需要取整 : 本次移动距离计算是一个除法的过程,会产生小数。而像素一般是整数
(2)没有误差 : 核心公式到了后面,都是1px的移动。
不需要边界检测 : 超过目标位置,清除定时器 并且 元素复位
需要终点检测 : 到达终点, 清除定时器
3.缓动动画封装思路
(1)解决代码冗余 -> 函数
(2)解决 移动距离 不限 -> 函数参数
(3)解决 移动元素 不限 -> 函数参数
(4)解决 移动方向 不限
(5)解决 移动属性 不限 -> 目前只能水平移动, 无法上下移动,无法改变宽高
(6)解决 移动属性数量 不限 -> 目前一次只能改变一个属性
最终动画 : 可以移动任意元素, 任意属性(不限数量) , 还可以移动多次
*/
/*
1.发现问题 : 层级与透明度没有动画
2.分析问题
层级 : 变化是一个瞬间的过程,没有动画的
透明度 :范围是 0-1的小数
(1)需要使用parseFloat取小数
(2)透明度属性值是 number,没有px
(3)浮点型存在精度丢失 : 需要放大100倍计算 (透明度最大保留小数点两位)
3.解决问题
层级 : 直接赋值,不做动画
*/
HTML 块
<input type="button" value="左右移动到800" id="btn1" />
<input type="button" value="上下移动到400" id="btn2" />
<div id="box"></div>
<div id="box1"></div>
js实现缓动动画代码
var box = document.querySelector('#box');//红色
//1. 红色缓动到400
document.querySelector('#btn1').onclick = function () {
animationSlow(box, {
left: 300,
top: 300,
width: 300,
height: 300,
zIndex: 1,
opacity: 0.5,
backgroundColor:'yellow'
});
};
//2. 红色缓动到800
document.querySelector('#btn2').onclick = function () {
animationSlow(box, {
left: 100,
top: 200,
width: 300,
height: 400,
});
};
/**
* @description: 缓动动画
* @param {type} ele : 要移动的元素
* @param {type} attrs : 要移动的属性对象
* @param {type} fn : 回调函数,可选。 (如果用户传了,则动画结束后执行fn中的代码)
* @return:
*/
function animationSlow(ele, attrs, fn) {
//1.清除以前的定时器,以本次为准
clearInterval(ele.timeID);
//2.开始本次移动
ele.timeID = setInterval(function () {
/*定时器每一次移动,结果只有两种情况。 要么全部到达终点,要么没有
开关思想三步法
a. 提出假设 var isAllOk = true
b. 验证假设
c. 根据开关结果实现需求
*/
//第一步 : 提出假设
var isAllOk = true;
//第二步 : 验证假设 (遍历对象属性,每一个属性进行移动)
for (var key in attrs) {
var attr = key;
var target = attrs[key];
if (key == 'zIndex' || key == 'backgroundColor') {
//层级没有动画,直接赋值
ele.style[attr] = target;
} else if (key == 'opacity') {//透明度单独处理
//2.1 获取元素当前位置
/*(1)透明度是0-1小数,需要parseFloat */
var current = parseFloat(getComputedStyle(ele)[attr]);
/* (2)透明度存在浮点型精度丢失:放大100倍计算 */
current *= 100;
target *= 100;
//2.2 计算本次移动距离 = (目标位置 - 当前位置)/10
var step = (target - current) / 10;
//取整 : 从左往右 : step正数 向上取整 从右往左:step负数 向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//2.3 开始移动
current += step;
/* (3)透明度是0-1小数,没有px */
ele.style[attr] = current/100;
//2.4 终点检测: 到达终点,清除定时器结束运动
//假设不成立 : 只要有属性没有到达终点
if (current != target) {
isAllOk = false;
};
}
else {
//2.1 获取元素当前位置
/* 注意点: getComputedStyle获取的是字符串类型,需要转成数字 */
var current = parseInt(getComputedStyle(ele)[attr]);
//2.2 计算本次移动距离 = (目标位置 - 当前位置)/10
var step = (target - current) / 10;
//取整 : 从左往右 : step正数 向上取整 从右往左:step负数 向下取整
step = step > 0 ? Math.ceil(step) : Math.floor(step);
//2.3 开始移动
current += step;
ele.style[attr] = current + 'px';
//2.4 终点检测: 到达终点,清除定时器结束运动
//假设不成立 : 只要有属性没有到达终点
if (current != target) {
isAllOk = false;
};
}
};
//第三步:根据开关结果实现需求
if (isAllOk) {
//清除定时器
clearInterval(ele.timeID);
//动画结束,开始执行回调函数 (用户传递了fn,且为函数才执行)
if (typeof fn == 'function') {
fn();
};
};
}, 20);
};
``