运动的本质
- 通过计时器每隔一段时间移动dom元素
- 定位
正向 终点值大于起点值
反向 终点值小于起点值
封装简易动画函数
注意函数需要传递2个参数,动画对象和移动到的距离
// 封装动画函数 obj目标对象 target目标位置
function move(obj ,target){
clearInterval(obj.timer); // 清除原有定时器
// 元素节点本质是对象
// 给不同元素记录不同的定时器
obj.timer = setInterval(function () {
if(obj.offsetLeft >= target ){
// 停止动画(本质是停止计时器)
clearInterval(obj.timer);
}
else{
obj.style.left = obj.offsetLeft + 50 + 'px';
}
},50)
}
或者
function animate(ele, end) {
clearInterval(timer);
var cur = ele.offsetLeft; // 元素开始的位置
end = parseFloat(end);
var speed = end >= cur ? 10 : -10; // end > cur正向运动
timer = setInterval(function () {
cur += speed; // 每隔一段时间 在原有基础上增加对应值
ele.style.left = cur + "px"; //
// 正向运动 (终点值大于起点值)
if (Math.abs(end - cur) <= Math.abs(speed)) { // 理想情况 cur == end
clearInterval(timer);
ele.style.left = end + "px";
}
}, 20);
}
多属性运动动画
原有封装,只能修改left不能改top,width 和height
function animate(ele, attr, end) {
clearInterval(timer);
// var cur = ele.offsetLeft; // 元素开始的位置
var cur = parseFloat(getStyle(ele, attr));
end = parseFloat(end);
var speed = end >= cur ? 10 : -10; // end > cur正向运动
timer = setInterval(function () {
cur += speed; // 每隔一段时间 在原有基础上增加对应值
// ele.style.left = cur + "px";
ele.style[attr] = cur + "px";
// 正向运动 (终点值大于起点值)
if (Math.abs(end - cur) <= Math.abs(speed)) { // 理想情况 cur == end
clearInterval(timer);
ele.style[attr] = end + "px";
}
}, 20)
}
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currenStyle[attr];
}
}
多属性运动动画之opacity
如果属性为opacity,取值时扩大100倍,赋值时,缩小100倍
function animate(ele, attr, end) {
clearInterval(timer);
// var cur = ele.offsetLeft; // 元素开始的位置
if (attr == 'opacity') { //如果是opacity 取值时扩大100倍 赋值时缩小100倍
var cur = parseFloat(getStyle(ele, attr)) * 100;
end = parseFloat(end) * 100;
} else {
var cur = parseFloat(getStyle(ele, attr));
end = parseFloat(end);
}
var speed = end >= cur ? 10 : -10; // end > cur正向运动
timer = setInterval(function () {
cur += speed; // 每隔一段时间 在原有基础上增加对应值
// ele.style.left = cur + "px";
// 赋值时 如果是opacity 缩小100倍;
if (attr == "opacity") {
ele.style[attr] = cur / 100;
} else {
ele.style[attr] = cur + "px";
}
// 正向运动 (终点值大于起点值)
if (Math.abs(end - cur) <= Math.abs(speed)) { // 理想情况 cur == end
clearInterval(timer);
if (attr == "opacity") {
ele.style[attr] = end / 100;
} else {
ele.style[attr] = end + "px";
}
}
}, 20)
}
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currenStyle[attr];
}
}
匀速运动
speed = end >= cur ? 10 : -10
function animate(ele, attr, end) {
clearInterval(timer);
if (attr == "opacity") { //如果是opacity(0-1) 取值是 扩大100倍(0-100) 赋值时缩小100倍
var cur = parseFloat(getStyle(ele, attr)) * 100; // 传统的取值方式 + 去单位
end = parseFloat(end) * 100;
} else {
// var cur = ele.offsetLeft; // 元素开始的位置(快捷取值)
var cur = parseFloat(getStyle(ele, attr)); // 传统的取值方式 + 去单位
end = parseFloat(end);
}
// 匀速运动
var speed = 0; // end > cur 正向运动
timer = setInterval(function () {
// 匀速运动
// speed = end >= cur ? 10 : -10
// 加速运动 每隔一段时间 速度有稳定的提升 v = 1/2 at^2
// speed = speed + 1; // 每隔10ms 速度加5
console.log(speed);
cur += speed; // 每隔一段时间 在原有基础上增加对应值
if (attr == "opacity") {
ele.style[attr] = cur / 100; //
} else {
ele.style[attr] = cur + "px"; //
}
// 正向运动 (终点值大于起点值)
if (Math.abs(end - cur) <= Math.abs(speed)) { // 理想情况 cur == end
clearInterval(timer);
if (attr == "opacity") {
ele.style[attr] = end / 100; // 到达终点
} else {
ele.style[attr] = end + "px"; // 到达终点
}
}
}, 10);
}
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
加速运动动画效果
speed = speed + 1
每隔一段时间,速度有稳定的提升
// 此处只能修改left 不能改 top ,width height
function animate(ele, attr, end) {
clearInterval(timer);
if (attr == "opacity") { //如果是opacity(0-1) 取值是 扩大100倍(0-100) 赋值时缩小100倍
var cur = parseFloat(getStyle(ele, attr)) * 100; // 传统的取值方式 + 去单位
end = parseFloat(end) * 100;
} else {
// var cur = ele.offsetLeft; // 元素开始的位置(快捷取值)
var cur = parseFloat(getStyle(ele, attr)); // 传统的取值方式 + 去单位
end = parseFloat(end);
}
// 匀速运动
var speed = 0; // end > cur 正向运动
timer = setInterval(function () {
// 匀速运动
// speed = end >= cur ? 10 : -10
// 加速运动 每隔一段时间 速度有稳定的提升 v = 1/2 at^2
speed = speed + 1; // 每隔10ms 速度加5
console.log(speed);
cur += speed; // 每隔一段时间 在原有基础上增加对应值
if (attr == "opacity") {
ele.style[attr] = cur / 100; //
} else {
ele.style[attr] = cur + "px"; //
}
// 正向运动 (终点值大于起点值)
if (Math.abs(end - cur) <= Math.abs(speed)) { // 理想情况 cur == end
clearInterval(timer);
if (attr == "opacity") {
ele.style[attr] = end / 100; // 到达终点
} else {
ele.style[attr] = end + "px"; // 到达终点
}
}
}, 10);
}
function getStyle(ele, attr) {
if (window.getComputedStyle) {
return window.getComputedStyle(ele)[attr];
} else {
return ele.currentStyle[attr];
}
}
缓动动画效果
缓动动画就是让元素运动速度有所变化,最常见的是让速度慢慢停下来
- 让盒子每次移动的距离慢慢变小,速度就会慢慢落下来
- 核心算法:(目标值-现在的位置)/ 缓冲因子 作为每次移动的距离步长
- 缓冲因子一般为8-12
- 停止的条件是:让当前盒子位置等于目标位置就停止定时器
- 注意步长值是需要取整的
缓冲运动的问题
a.速度不断递减无限接近0,但是不等于0,运动的元素无限接近0
正向运动(终点值>起点值) 速度是正值
反向运动(终点值<起点值) 速度是负值
speed = (end-current)/10
// 如果step大于0为正值,则往大了取,向上取整
var step = Math.ceil((target - obj.offsetLeft) / 10);
// 如果step小于0位负值,则往小了取,向下取整
var step = Math.floor((target - obj.offsetLeft) / 10);
// 即
var step = (target - obj.offsetLeft) / 10;
step = step > 0 ? Math.ceil(step) :Math.floor(step);
匀速动画就是 盒子是当前的位置+固定的值
缓动动画就是 盒子当前的位置+变化的值(目标值-现在的位置)/10)
// 缓动动画
// 封装动画函数 obj目标对象 target目标位置
function move(obj ,target){
clearInterval(obj.timer); // 清除原有定时器
// 获得盒子的当前位置
obj.timer = setInterval(function () {
// 步长值写到定时器的里面
var step = (target - obj.offsetLeft) / 10;
if(obj.offsetLeft = target ){
// 停止动画(本质是停止计时器)
clearInterval(obj.timer);
}
else{
// 把每次加50 这个布长值,改为一个慢慢变小的值 布长公式:(目标值-现在的位置) / 10
obj.style.left = obj.offsetLeft + step + 'px';
}
},15)
}
链式运动
运动结束之后,可以执行其他的操作(原理 接收一个回调函数,结束时调用)
动画函数添加回调函数
回调函数原理:函数可以作为一个参数。将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数,这个过程就叫做回调。
- 回调函数写的位置:定时器结束的位置
封装步骤总结
- 原生手写,正向运动和反向运动
- 封装成简易运动函数 offsetLeft
- 封装成多属性运动 let/top/width/height
- 封装成多属性运动 => opacity
- 加速运动/缓冲运动 => 多类型运动
- 多元素运动 ele.timer
- 链式运动(运动结束之后,执行回调函数)