一.缓冲运动
需求
小球下落的过程中速度逐渐变小,到达底部时速度变为零
要点
通过实时比较运动总路程box.offsetHeight-ball.offsetHeight.
和ball.offsetTop(小球距离box顶部的距离)
把两者之差赋给变量speed,
就可以得到一个ball.offsetTop不断增加,
speed有初始值但不断减小至0的运动过程
完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<style>
.box {
position: relative;
width: 300px;
height: 500px;
background-color: antiquewhite;
}
#ball {
position: absolute;
left: 0;
top: 0;
width: 50px;
height: 50px;
background-color: blue;
border-radius: 50%;
margin: 0px;
}
</style>
<div class="box">
<dov id="ball"></dov>
</div>
<script>
var ball = document.querySelector("#ball");
var box = document.querySelector(".box");
var timer = null;
var target = box.offsetHeight - ball.offsetHeight;
ball.onclick = function() {
clearInterval(timer);
timer = setInterval(() => {
var speed = (target - ball.offsetTop) / 10; //ball.offsetTop增大,speed减小
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); //保持四舍五入整数
// console.log(speed);
if (ball.offsetTop + speed >= target) {
clearInterval(timer);
} else {
ball.style.top = ball.offsetTop + speed + "px";
}
}, 100);
}
</script>
</body>
</html>
重点代码
var ball = document.querySelector("#ball");
var box = document.querySelector(".box");
var timer = null;
var target = box.offsetHeight - ball.offsetHeight;
ball.onclick = function() {
clearInterval(timer);
timer = setInterval(() => {
var speed = (target - ball.offsetTop) / 10; //ball.offsetTop增大,speed减小
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); //保持四舍五入整数
// console.log(speed);
if (ball.offsetTop + speed >= target) {
clearInterval(timer);
} else {
ball.style.top = ball.offsetTop + speed + "px";
}
}, 100);
// move(ball);
}
二.把其运动过程封装成一个move函数
只需要在鼠标点击事件中调用这个函数就行了
重点代码
var ball = document.querySelector("#ball");
var box = document.querySelector(".box");
ball.onclick = function() {
move(ball);
}
//封装缓冲运动的函数
function move(ele) {
var times = null;
var target = box.offsetHeight - ele.offsetHeight;
clearInterval(times);
times = setInterval(() => {
var alpha = ele.offsetTop;
var speed = Math.ceil((target - alpha) / 10); //只读属性上偏移量alpha增大,speed减小
console.log(`运动路程:${target},当前路程:${alpha},当前速度:${speed}`);
if ((alpha + speed) > target) {
ele.style.top = target + 'px';
} else {
ele.style.top = speed + alpha + 'px';
}
if (Math.abs(speed) < 1) clearInterval(times);
}, 30);
}
三.封装一个抽象的,适配性更高的运动函数
封装一个运动函数,让其适配不止一种运动情况,
不仅仅可以满足元素的高度发生改变这样的一种情况,
让以元素的其他属性(宽高背景色透明度等等)的改变为基础的运动事件都可以用得上
*注意getStyle的形参应该是ele,也就是div对象,而不是obj(即元素属性)
代码
//运动函数封装
var timer = null;
//ele:运动元素如div,obj:div元素的属性和属性值构成的对象,cb:callback回调函数
function move(ele, obj, cb) {
//定时器先清除再调用
clearInterval(timer);
timer = setInterval(() => {
// 设置一个清除定时器与否的开关
var onOff = false;
// 遍历运动属性obj[i],如width,height,opacity,backgroundColor等等
for (var attr in obj) {//attribute:属性
// 获取运动元素的实时运动属性值
//var tmpPos = parseInt(window.getComputedStyle(obj[attr])); //100px,red等等可能的属性值
//考虑IE兼容,封装成一个函数getStyle
var tmpPos =parseInt(getStyle(ele,attr));
// 计算speed
var speed = (obj[attr] - tmpPos) / 10; //属性的目标值(如前例的target)-属性的当前值(如前例的alpha),除以10 是为了提高运动过程的精细程度
speed > 0 ? Math.ceil(speed) : Math.floor(speed); //因为除以10可能会产生小数,因此|speed|向上取整
// 更新运动属性
ele.style[attr] = tmpPos + speed + "px"; //举例:div.style.width
// 判断达到目标值
if ((speed + tmpPos) == obj[attr]) onOff = true;
}
// 判断开关,写在for循环外面
if (onOff) clearInterval(timer);
}, 30);
}
function getStyle(ele,attr)(
if(ele.currentStyle[attr]) return ele.currentStyle[attr];//兼容IE
else return getComputedStyle(ele)[attr];//通用
)
四.调用运动函数应用场景
<div id="box" style="width:50px;height:50px;position:absolute;background:red;border-radius: 50%;left:100px;">
</div>
<script>
// 获取节点
let boxObj = document.getElementById('box');
boxObj.onclick = function() {
move(this, { //调用运动函数
top: 400
}, function() {
alert("运动完成!");
});
};
// 运动三要素:元素 目标 属性
function move(eleObj, objArr, callback) {
var timer = '';
// 使用之前先清空定时器
clearInterval(timer);
timer = setInterval(() => {
// 设置清除定时器的判断开关
var onOff = false;
// 遍历运动元素的属性
for (var attr in objArr) {
// 获取元素的实时属性值
var tmpPos = parseInt(getStyle(eleObj, attr)); //调用getStyle
// 计算speed
var speed = (objArr[attr] - tmpPos) / 10;
speed > 0 ? Math.ceil(speed) : Math.floor(speed);
// 更新运动属性:让元素开始运动
eleObj.style[attr] = speed + tmpPos + 'px';
// 判断临界值
if (speed + tmpPos == objArr[attr]) onOff = true;
}
// 判断清空定时器
if (onOff) {
clearInterval(timer);
// 如有回调函数就调用
if (callback) return callback();
}
}, 30);
}
// 获取元素实时的属性值
function getStyle(obj, attr) {
if (obj.currentStyle) return obj.currentStyle[attr]; //兼容IE
else return getComputedStyle(obj)[attr]; //通用
}
</script>