当今的生活质量越来越高,人们对于自身的身体素质也更加重视。对于运动的热情,逐渐高涨起来。
人类的体育锻炼运动中,看见最多的就是篮球了吧。本人不会打篮球,因为篮球看着太吓人, 我的小身板也不允许我去打篮球,打篮球的过程中总会有磕磕撞撞,导致受伤。
篮球运动的规则不就是,把球扔进篮球篮子嘛。so eazy 。再换句话说不就是大家都知道的抛物运动嘛。
提到抛物运动,回想起高中物理,是不是大家对于打篮球就充满了‘自信’。手抬高,一扔,进了!!!
今天介绍的也是抛物运动的实现,不过不是在生活中实现它。而是在页面中实现它,而实际上在也页面上投篮的就是JavaScript。它才是本场比赛的篮球运动员。
在讲抛物线运动之前,要明白抛物线运动的实质。或者将其分解为两个方向的运动。
1.首先是竖直方向上的运动,就是单纯的高度逐渐减小的过程
2.其次就是水平方向上的运动,也就是单纯的往一个方向位移过程。
将这两个分支运动合起来就是我们的打篮球了。
让我们的JavaScript上场表演吧!!!
垂直方向:
垂直方向的运动,在页面中就是高度的减小。
下面是一个简单的例子:篮球的重力回弹的效果。
第一阶段的过程就是球的下落过程,也就是球的高度top的不断增大。
在top值增大的过程中也就需要,不断地给top增加一个speed步进值。
先是基本的css和html样式和结构
<style type="text/css">
.cont {
width: 1000px;
height: 600px;
background: #eee;
margin: 20px auto;
position: relative;
}
.box {
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 0;
border-radius: 50%;
}
</style>
<body>
<div class="cont">
<div class="box"></div>
</div>
</body>
接下来就是我们今天的主角:JavaScript登场啦!!!
第一步是获取html当中的节点对象,才能进行操作。
<script>
// 1 获取节点
let contObj = document.querySelector('.cont');//篮球可以活动的范围,节点对象
let boxObj = document.querySelector('.box');//篮球节点对象
</script>
第二步进行我们所需要的变量的声明准备。
其中重要的变量有:
1. 因为地球的原因,有重力,所以在步进值speed的基础上,应该还要增加重力带来的加速度。
2.target目标,就是篮球在范围内最大的可运动的高度(要减去球自身的高度)。
3.要想让球的高度减少,就应该让球在反向的时候,让它的speed比原来小就可以了,所以给speed乘以一个小于1的数,就可以让反向高度变小。
// 2 设置变量
let speed = 10; //步进值
let g = 2; //重力的影响
let times = ''; //清除定时器的标识符
let target = contObj.offsetHeight - boxObj.offsetHeight; // 小球的最大目标值
第三步就是具体的实现方法 :
//球绑定点击事件
ball.addEventListener('click', function() {
clearInterval(timer) //防止定时器累加
timer = setInterval(function() { //设置定时器
speed += g; //步长增加
if (speed < target - ball.offsetTop) { //高度小于目标高度时
ball.style.top = ball.offsetTop + speed + 'px'; //设置球的高度样式
} else if (speed >= target - ball.offsetTop) { //当到盒子目标高度时
ball.style.top = target + 'px'; //让球直接到达底部
speed = -parseInt(speed) * 0.8; //让步长变负,高度减小,球往上走
if (Math.abs(speed) < 1) { //当步长小于1
clearInterval(timer); //停止
}
}
}, 30)
})
完成上述的垂直方向的运动之后,就可以往其加上水平方向的代码了。
垂直方向和水平方向的结合:
水平方向的原理其实和垂直方向差不多,你也可以想象将页面顺时针旋转90度。
实现方法:
第一步获取节点对象,同上。
第二步准备需要的变量。因为要在水平方向上变化,肯定也需要一个水平的步进值,leftSpeed,也同样需要往左的最大范围值leftTarget,也是 篮球在范围内最大的可运动的宽度再减去球本身的宽度。增加了一个count值用来,累积运动次数,每5次增加一个重力,让它能跳更久,到底部的时间增加。
// 设置left的步进值和最大值
var leftSpeed = 20;
var leftTarget = 1000 - ballObj.offsetWidth;
var count = 0; // 累计运动次数
第三步,只需要给球在高度样式的位置添加水平位移样式即可
ballObj.style.left = leftSpeed + ballObj.offsetLeft + 'px'; //给球位移样式
在这里需要注意:
球可能会从水平方向滚出去。所以还需要给球设置边界:
思路其实很简单:只需要等球到达可运动范围的最大值的时候,让它的步进值反向。
if (ballObj.offsetLeft >= leftTarget) { //当球到达最右边届
leftSpeed = -leftSpeed; //步进值反向
}
if (ballObj.offsetLeft <= 0) { //当球到达最右边届
leftSpeed = -leftSpeed; //步进值反向
}
综上实现得到的代码 :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
.box {
width: 1000px;
height: 400px;
margin: 50px auto;
position: relative
}
#ball {
width: 50px;
height: 50px;
background: red;
border-radius: 50%;
position: absolute;
left: 0px;
top: 0;
}
.line {
width: 1000px;
height: 1px;
background: black;
position: absolute;
top: 300px;
left: 0px;
}
</style>
</head>
<body>
<div class="box">
<div id="ball"></div>
<div class="line"></div>
</div>
</body>
<script type="text/javascript">
// 1 获取节点
var ballObj = document.getElementById('ball');
var lineObj = document.querySelector('.line')
// 2 设置top的步进值,和最大值.
// 定时器的计数器
var topSpeed = 5;
var topTarget = 300 - ballObj.offsetHeight; // top的临界值
var count = 0; // 累计运动次数
var g = 1; // 重力值的设置
// 设置left的步进值和最大值
var leftSpeed = 20;
var leftTarget = 1000 - ballObj.offsetWidth;
//定时器标识
var times = '';
ballObj.onclick = function() {
clearInterval(times); //清除定时器累加
times = setInterval(function() {
count++;
if (count % 5 == 0) { //运动5次增加一个重力
topSpeed += g; //高度步进增加
}
if (topSpeed + ballObj.offsetTop > topTarget) { //当大于目标值
topSpeed = -topSpeed * 0.8; //步进变负,上升
ballObj.style.top = topTarget; //强制到最下面
if (Math.abs(topSpeed) < 1) clearInterval(times); //步进值小于1,清除定时器
} else {
ballObj.style.top = topSpeed + ballObj.offsetTop + 'px'; //给球下降的样式
ballObj.style.left = leftSpeed + ballObj.offsetLeft + 'px'; //给球位移样式
}
if (ballObj.offsetLeft >= leftTarget) { //当球到达最右边届
leftSpeed = -leftSpeed; //步进值反向
}
if (ballObj.offsetLeft <= 0) { //当球到达最右边届
leftSpeed = -leftSpeed; //步进值反向
}
}, 30)
}
</script>
</html>
前两个例子大同小异,方法基本相同。所以可以想办法封装一个运动函数。
运动函数的目的就是,只要输入运动的三要素{谁运动,运动方向,目标值}。我们就能实现运动效果。
其中获取元素的实时属性的时候,需要考虑是否是行内样式。如果不是行内样式,要添加兼容性获取样式的封装函数。
// 获取元素的非行内样式的封装函数
function getPos(obj, attr) {//参数为对象,和属性
if (obj.currentStyle) { // 获取css的样式
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj)[attr]
}
}
得到元素的实时位置之后就可以进行下一步封装运动函数了。
var times = '';
function move(ele, obj, back) { //运动函数
clearInterval(times); //清除定时器,以免累加
times = setInterval(function() { //定时器
var onOff = true;
for (let index in obj) { //遍历对象中的所有属性,index代表属性
var value = parseInt(getPos(ele, index)); //获取元素属性对应的样式的实时值
var speed = (obj[index] - value) / 10; //设置步进值
speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed); //取整,方便计算
if (value == obj[index]) onOff = true; // 当一个属性运动到位置,设置开关状态
ele.style[index] = value + speed + 'px'; //设置元素的样式
}
for (var i in obj) { //再次遍历对象中的所有属性
if (obj[i] !== parseInt(getPos(ele, i))) { //如果存在实时值和目标值不相等。
onOff = false; //开关状态为假
break;
}
}
if (onOff) { //开关为真,则清除定时器
clearInterval(times);
back && back(); //调用回调函数
}
}, 30)
}
// 获取元素的非行内样式的封装函数
function getPos(obj, attr) {
if (obj.currentStyle) { // 获取css的样式
return obj.currentStyle[attr];
} else {
return getComputedStyle(obj)[attr]
}
}
调用封装运动函数的方法:
首先应该得到一个目标值(可以是任何数据)。target
再比如给一个按钮绑定点击事件,开始运动。同样需要运动三要素。
ele为要运动元素名,第二个参数为对象,对象中是需要运动的属性和属性值,最后是回调函数,回调函数可以根据情况添加或者不加。
btn.onclick = function() {
move(ele, {
left: target,
height: 300
}, function() {})
}
有了运动函数就可以随意添加变化的属性值了,再也不用担心要添加的变量多了!
举一个使用封装运动函数实现的例子:
第一个要求:让红色方块移动到黑色竖线。
第二个要求:在移动的过程中方块的高度要变化到300px。
实现步骤:
1.首先是移动的元素是:方块。
2.变化的属性:方块的height,方块距离屏幕的left值。
3.目标值:height的目标值就是300px,left的目标值设为target就应该是方块的offsetLeft值减去竖线的offsetLeft值。
// 1 获取节点
let btnObj = document.getElementById('btn'); //获取按钮节点对象
let divObj = document.querySelector('div'); //获取方块节点对象
// 目标值
let target = divObj.offsetLeft - divObj.nextElementSibling.offsetLeft;
//给按钮绑定点击事件
btnObj.onclick = () => {
//调用移动函数
move(divObj, {
left: target,
height: 300
}, function() {
console.log('移到目标啦!!!');
})
}
再将上面封装好的运动函数,加到点击事件后面即可完成。
运动函数的封装就完成了!