运动基础
- 在JavaScript中,如何让一个页面元素动起来?
首先,我们需要了解的是,在JavaScript中如何让一个页面元素动起来。
我们先来实现一个简单的功能,当我们点击按钮之后,让一个元素动起来。并且到达500的边界之后立刻停止下来。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#d1 {
100px;
height: 100px;
background-color: red;
position: absolute;
top:100px;
left: 200px;
}
</style>
</head>
<body>
<button id="btn">点击运动</button>
<div id="d1"></div>
</body>
<script>
// 点击按钮,让div横向的运动起来
// 1. 获取元素
let oBtn = document.getElementById('btn');
let oDiv = document.getElementById('d1');
let iTimer = null;
// 点击按钮,让元素一直运动 ,需要使用到的知识点:定时器
oBtn.onclick = ()=>{
iTimer = setInterval(()=>{
// 点击按钮之后,让div的位置在当前的基础之上每次增加10px的距离
// oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; // 虽然此代码可以让div动起来,但是我们需要div在运动之后到达某个边界就立刻停止,所以需要将此句代码改为一个判断
if (oDiv.offsetLeft === 500) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv.style.left = oDiv.offsetLeft + 10 + 'px';
}
},30);
};
</script>
</html>
在上面的代码中,我们点击按钮之后,元素已经可以直接进行移动,但是却存在一个问题,什么问题呢?
当我们点击按钮之后,元素始终以10px的匀速进行运动,到达500的临界然后停止。 但是我们的问题是,速度可能会变,例如将速度变为7px,就不能够
准确的到达500的临界值。
例如:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#d1 {
100px;
height: 100px;
background-color: red;
position: absolute;
top:100px;
left: 200px;
}
</style>
</head>
<body>
<button id="btn">点击运动</button>
<div id="d1"></div>
</body>
<script>
// 点击按钮,让div横向的运动起来
// 1. 获取元素
let oBtn = document.getElementById('btn');
let oDiv = document.getElementById('d1');
let iTimer = null;
// 点击按钮,让元素一直运动 ,需要使用到的知识点:定时器
oBtn.onclick = ()=>{
iTimer = setInterval(()=>{
// 点击按钮之后,让div的位置在当前的基础之上每次增加10px的距离
// oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; // 虽然此代码可以让div动起来,但是我们需要div在运动之后到达某个边界就立刻停止,所以需要将此句代码改为一个判断
if (oDiv.offsetLeft === 500) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv.style.left = oDiv.offsetLeft + 7 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
};
</script>
</html>
出现这种情况的原因是因为运动的临界值必须能够被运动的速度(也就是oDiv.offsetLeft + 7 + 'px',表示每次执行移动的距离)整除。
上面的代码当中, 因为临界值不能够被速度整除,所以,最终元素始终达到不了临界值,那么元素就没有办法在到达临界值时停止。
同时在上面的代码中的另外一个问题是,当我们每点击一次运动按钮,元素的速度就会变得更快,原因很简单,就是我们设置的定时器发生了累加。
那么该如何解决定时器累加的问题呢?
我们可以在每次开始运动之前先清楚一次定时器。
oBtn.onclick = ()=>{
/*
* 为了防止定时器累加,在每次开始定时器之前,先清楚掉一个定时器
* */
clearInterval(iTimer);
iTimer = setInterval(()=>{
// 点击按钮之后,让div的位置在当前的基础之上每次增加10px的距离
// oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; // 虽然此代码可以让div动起来,但是我们需要div在运动之后到达某个边界就立刻停止,所以需要将此句代码改为一个判断
if (oDiv.offsetLeft === 500) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv.style.left = oDiv.offsetLeft + 7 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
};
总结:在上面的代码中,是我们一般让一个元素运动起来的基本流程。下面进行一个简单的总结:
- 首先是存在的问题:处于匀速运动的元素没有办法进行在不整除的情况下在临界点停止。
- 在上面的代码中,可以将整个过程大致分为三个步骤:
- 清除定时器,保证只有一个定时器在执行
- 开启定时器
- 开始运动(需要同时加入一个判断,以便在需要的时候或者满足某个要求时停止运动)
简单运动的封装
为了让我们上面的代码可以具备更高的复用性,下面我们把上面的代码进行一个简单的封装。
示例:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#d1 {
100px;
height: 100px;
background-color: red;
position: absolute;
top:100px;
left: 200px;
}
</style>
</head>
<body>
<button id="btn">点击运动</button>
<div id="d1"></div>
</body>
<script>
// 点击按钮,让div横向的运动起来
// 1. 获取元素
let oBtn = document.getElementById('btn');
let oDiv = document.getElementById('d1');
let iTimer = null;
// 点击按钮,让元素一直运动 ,需要使用到的知识点:定时器
oBtn.onclick = ()=>{
startMove();
// 将运动相关的内容全部放到startMove这个函数中,然后调用既可以让元素进行运动
function startMove() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv.offsetLeft === 500) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
};
</script>
</html>
在上面的代码中,我们将运动相关的内容放到了一个函数startMove
中,并且调用了这个函数,下面来根据这个函数进行案例的开发。
案例1:分享到功能
首先,先来实现基本的功能:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#div1 {
100px;
height: 200px;
background:red;
position: absolute;
left: -100px;
top: 200px;
}
#div2 {
30px;
height: 70px;
background: black;
position:absolute;
right:-30px;
top: 70px;;
color:#fff;
text-align: center;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">分享到</div>
</div>
</body>
<script>
// 1. 首先获取两个元素
let oDiv1 = document.getElementById('div1');
let oDiv2 = document.getElementById('div2');
let iTimer = null;
// 给为父级的div绑定mouseover 和 mouseout事件
oDiv1.onmouseover = function() {
this.style.left = 0 + 'px'; // 鼠标移入,让div元素出现
};
oDiv1.onmouseout = function() {
this.style.left = -100 + 'px'; // 鼠标移出,让div隐藏
};
</script>
</html>
上面的代码中,我们鼠标移入,元素出现。鼠标移出,元素消失。
下面我们来使用我们的startMove函数,给元素出现和消失加上一个过渡的效果。
我们的startMove函数如下:
function startMove() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv.offsetLeft === 500) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv.style.left = oDiv.offsetLeft + 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
我们想要在分享到
功能里使用这个函数,我们需要对我们的函数根据分享到的需求进行一定程度的更改。
首先是,将我们函数中的oDvi
更改为oDiv1
。
其次是我们分享到案例的需求在鼠标移入时需要将元素逐渐的显示,而鼠标移出时,需要将元素逐渐的隐藏。所以我们需要将startMove
函数创建两个
,并且当鼠标移出时,速度应该将函数中的+10
变为-10
。
当然,也别忘了去更该元素边界的值。当移出时,边界为0,移入时,边界为-100.
如下:
鼠标移入时调用的startMove1函数:
function startMove1() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === 0) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv.offsetLeft + 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
鼠标移出时调用的startMove2函数:
function startMove() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === -100) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv.offsetLeft - 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
我们先来将这两个函数放在代码中,进行测试。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#div1 {
100px;
height: 200px;
background:red;
position: absolute;
left: -100px;
top: 200px;
}
#div2 {
30px;
height: 70px;
background: black;
position:absolute;
right:-30px;
top: 70px;;
color:#fff;
text-align: center;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">分享到</div>
</div>
</body>
<script>
// 1. 首先获取两个元素
let oDiv1 = document.getElementById('div1');
let oDiv2 = document.getElementById('div2');
let iTimer = null;
// 给为父级的div绑定mouseover 和 mouseout事件
oDiv1.onmouseover = function() {
// this.style.left = 0 + 'px'; // 鼠标移入,让div元素出现
startMove1();
};
oDiv1.onmouseout = function() {
// this.style.left = -100 + 'px'; // 鼠标移出,让div隐藏
startMove2();
};
function startMove1() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === 0) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv1.offsetLeft + 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
function startMove2() {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === -100) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv1.offsetLeft - 10 + 'px'; // 一旦将每次的移动距离变为7px ,那么将不能停的下来.元素会一直运动
}
},30);
}
</script>
</html>
上面的代码中,我们通过创建两个startMove函数,并且对相应的参数进行修改,从而实现了给我们的分享到功能添加了过渡效果。
进一步升级:
当然,我们上面的代码中使用的函数其实是非常不灵活的,所以我们下面要做到事就是对之前的函数进行升级,从而让我们的函数具备更强的实用性。
首先我们再回过头来看下我们刚才写的两个函数,你会发现,大部分的代码其实都是相同的,只有个别的值是不同的,例如元素移动的边界,例如元素
单位时间内移动的距离。
我们将上面的两个函数合并成一个函数,只需要将不一样的值提取出来当做参数即可。
下面是合并之后的函数:
function startMove(iTarget,iSpeed) {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === iTarget) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv1.offsetLeft + iSpeed + 'px';
}
},30);
}
上面的函数升级完成之后,我们在重新的将这个函数应用到我们的分享到功能的代码当中去。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
#div1 {
100px;
height: 200px;
background:red;
position: absolute;
left: -100px;
top: 200px;
}
#div2 {
30px;
height: 70px;
background: black;
position:absolute;
right:-30px;
top: 70px;;
color:#fff;
text-align: center;
}
</style>
</head>
<body>
<div id="div1">
<div id="div2">分享到</div>
</div>
</body>
<script>
// 1. 首先获取两个元素
let oDiv1 = document.getElementById('div1');
let oDiv2 = document.getElementById('div2');
let iTimer = null;
// 给为父级的div绑定mouseover 和 mouseout事件
oDiv1.onmouseover = function() {
// this.style.left = 0 + 'px'; // 鼠标移入,让div元素出现
startMove(0,10);
};
oDiv1.onmouseout = function() {
// this.style.left = -100 + 'px'; // 鼠标移出,让div隐藏
startMove(-100,-10);
};
function startMove(iTarget,iSpeed) {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDiv1.offsetLeft === iTarget) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDiv1.style.left = oDiv1.offsetLeft + iSpeed + 'px';
}
},30);
}
</script>
</html>
上面的代码中,我们顺利的通过我们的startMove函数给分享到功能添加了过渡的效果。
图片的淡入淡出效果:
下面我们再来看另外的一个效果,图片的淡入淡出
,还是通过我们上面定义好的startMove
函数来实现效果。
首先,我们上面的函数当中,只是针对oDiv1
,为了让我们的函数可以处理任意的元素,我们将oDiv1
替换成函数的形参。
例如:
function startMove(oDom,iTarget,iSpeed) {
clearInterval(iTimer);
iTimer = setInterval(()=>{
if (oDom.offsetLeft === iTarget) {
// 清除定时器
clearInterval(iTimer);
}else { // 没有到达边界才能继续运动
oDom.style.left = oDom.offsetLeft + iSpeed + 'px';
}
},30);
}
上面的代码当中,我们将函数操作的元素提取出来,变成了函数的形参,这样做之后,我们就可以让我们的函数针对任意的元素。