js中匀速运动的基本原理:
用定时器不断的改变元素的某一属性,从而达到动态效果
由于动图实在是太麻烦(好吧,是我懒 '_>`),建议大家下载源码,方便同步演示
☛<a href="http://pan.baidu.com/s/1jI2MD0q">戳此下载源码</a>
提纲
- 简单的从左至右运动
- 终止运动
- 运动的速度控制
- 处理bug:由速度引起的无法终止运动
- 处理bug:达到目标后点击按钮仍向前运动
- 处理bug:多次点击按钮会使速度变快
- demo:div的鼠标移入滑出运动
- demo:透明度运动
简单的从左至右运动:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style type="text/css">
#div1{
width: 150px;
height: 80px;
background-color: #2470B4;
position: absolute;
top: 50px;
left: 100px;
}
</style>
<script type="text/javascript">
function startMove() {
var oDiv1 = document.getElementById("div1");
setInterval(function () {
//每30毫秒div1的left属性增加7
oDiv1.style.left = oDiv1.offsetLeft + 7 + "px";
}, 30);
}
</script>
</head>
<body>
<input type="button" value="开始运动" onclick="startMove();">
<div id="div1"></div>
</body>
</html>
这是最简单的运动了,点击按钮,蓝色div会一直向右走...
...一直走到天荒地老
由于我们没有设置终止,div会一直向右移动,现在我们来想办法让它停下来
终止运动
我们是通过定时器让div动起来的,想让它停下来,就得关掉定时器:
<script type="text/javascript">
var timer = null;
function startMove() {
var oDiv1 = document.getElementById("div1");
timer = setInterval(function () {
//让div1移动到500px停下来
if(oDiv1.offsetLeft == 500) clearInterval(timer);
//每30毫秒div1的left属性增加7
oDiv1.style.left = oDiv1.offsetLeft + 10 + "px";
}, 30);
}
</script>
用一个变量 timer 来存储定时器,方便关闭,在每次定时器启动的时候先判断是否达到终止条件
如果达到了就用 clearInterval(timer);
关闭定时器,停止运动
运动的速度控制
由之前的代码可以看出,真正控制运动的是
`oDiv1.style.left = oDiv1.offsetLeft + 10 + "px";`
而这个运动速度是由增量10
来决定的,增量越大,运动越快,反之亦然
为了方便变更速度,我们可以用一个变量 speed
来保存增量:
timer = setInterval(function () {
var speed = 7;
if(oDiv1.offsetLeft == 500) clearInterval(timer);
oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
}, 30);
这样改变speed
的值就可以改变速度了,这里我们改成了7
bug:由速度引起的无法终止运动
速度改为7之后出现了一个bug:div达到了终止条件依然还在移动
原因很明显,speed
为7即增量为7,而我们设置的初始left为100
也就是说,div1
的offsetLeft
永远也不会等于500,也就无法停止定时器停下来了
所以我们应该修改下终止条件:
改为oDiv1.offsetLeft >= 500
,这样就能保证不论speed
能否整除500,div都能停下来了
到目前为止,我们的div已经能动,能停了,但是依然漏洞百出
bug:达到目标后点击按钮仍向前运动
大家可以试下,第一次点击按钮可以让div动起来,停止后,再次点击按钮,div会蹿一下,点一下蹿一下,点一下蹿一下...
这是因为setInterval()
这个函数跟do{...}while()
有点像,do while是先执行一遍再判断,而前者是先运行一遍,再延时,运行时虽然达到了终止边界要停止定时器,但是这一遍是要运行完的,所以会向前走一个距离增量
解决办法非常简单,既然达到了终止条件,就应该不运行后面的代码了,把后面的代码用else
包起来就行了:
timer = setInterval(function () {
var speed = 7;
if(oDiv1.offsetLeft >= 500){
clearInterval(timer);
} else {
oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
oP.innerHTML = oDiv1.offsetLeft + "px";
}
}, 30);
这样就只有当oDiv1.offsetLeft < 500
时才会执行后面的代码
bug:多次点击按钮会使速度变快
最后这个小bug是非常常见的,先说说问题的原因吧,这是因为每次点击按钮都会开启一个定时器,假如要给定时器30毫秒的增量是10,点三次开启三个定时器的话30毫秒的增量就成了30,所以就越来越快
解决办法也十分有代表性,在每次点击按钮时先关闭定时器,再开启,这样就能保证只有一个定时器在运行:
clearInterval(timer);
timer = setInterval(function () {
var speed = 7;
if(oDiv1.offsetLeft >= 500){
clearInterval(timer);
} else {
oDiv1.style.left = oDiv1.offsetLeft + speed + "px";
oP.innerHTML = oDiv1.offsetLeft + "px";
}
}, 30);
demo:div的鼠标移入滑出运动
大家一定见过这种效果:一个小div悬浮在屏幕的一侧,鼠标移入时,小div连着一个大div一起滑出,鼠标移出时又收回去,只剩小div继续悬浮在屏幕一侧。
有了之前的经验,思路变得非常清晰:
- 把大div定位到屏幕外边隐藏起来
- 鼠标移入时:两个div移出,露出大div
- 鼠标移出时:两个div收回,只剩小div
html代码:
<body>
<div id="div1">
<div id="div2"></div>
</div>
</body>
CSS代码:
#div1{
width: 200px;
height: 400px;
border: 1px solid #2470B4;
position: absolute;
top: 100px;
left: -200px;
}
#div2{
width: 30px;
height: 100px;
background-color: #2470B4;
position: absolute;
top: 150px;
right: -30px;
}
js代码:
window.onload = function () {
var oDiv1 = document.getElementById("div1");
var timer = null;
oDiv1.onmouseover = function () {
clearInterval(timer);//先清除定时器,确保只有一个定时器在运行
//鼠标移入offsetLeft要增加,speed为正
var speed = 10;
timer = setInterval(function () {
if(oDiv1.offsetLeft == 0){ //鼠标移入offsetLeft由-200变为0
clearInterval(timer);
} else {
oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
}
}, 30)
}
oDiv1.onmouseout = function () {
clearInterval(timer);//先清除定时器,确保只有一个定时器在运行
//鼠标移入offsetLeft要减小,speed为负
var speed = -10;
timer = setInterval(function () {
if(oDiv1.offsetLeft == -200){ //鼠标移入offsetLeft由0变为-200
clearInterval(timer);
} else {
oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
}
}, 30)
}
}
实现效果虽然十分简单,但是写出来的代码重复的地方太多了,臃肿难看,不够优雅,我们想办法来改进一下
大家可以看出来,这里onmouseover
和onmouseout
调用的两个匿名函数几乎一模一样,只有两个关键的值不同——移动终点和速度的正负,而速度的正负可以有移动终点来判断,所以我们不妨重新定义一个函数toggleShow(target)
,把这两个值提取出来,统一成一个参数传进去,这样就可以把两个函数合二为一了:
window.onload = function () {
var oDiv1 = document.getElementById("div1");
var timer = null;
oDiv1.onmouseover = function () {
toggleShow(0);
};
oDiv1.onmouseout = function () {
toggleShow(-200);
};
function toggleShow(target) {
clearInterval(timer);
var speed = 0;
//根据target的位置来判断速度的正负
speed = target - oDiv1.offsetLeft > 0 ? 10 : -10;
timer = setInterval(function () {
if(oDiv1.offsetLeft == target){
clearInterval(timer);
} else {
oDiv1.style.left = oDiv1.offsetLeft + speed +"px";
}
}, 30)
}
}
比较一下,是不是精简了许多:)
demo:透明度运动
这个效果也挺常见的,鼠标移入div变得不透明,移出再变的半透明,又叫淡入淡出。
原理跟上个demo一样,只是这次改变的是透明度:
- 设置透明度的初始值为30(0.3)
- 鼠标移入时:透明度增加到100(1)
- 鼠标移出时:透明度减小到30(0.3)
html代码:
<body>
<div id="div1"></div>
</body>
CSS代码:
#div1{
width: 300px;
height: 200px;
background-color: #2470B4;
margin: 150px auto;
opacity: 0.5;
filter: alpha(opacity: 30);
}
css中不同浏览器的设置透明度的属性不同:
opacity:0.5 //for IE9, Firefox, Chrome, Opera, Safari
filter:alpha(opacity = 50) //for IE6, IE7, IE8
后者也可以写成:
filter:alpha(opacity:50) //for IE6, IE7, IE8
js代码:
window.onload = function () {
var oDiv1 = document.getElementById("div1");
var timer = null;
var alpha = 30;
function toggleShow(target) {
clearInterval(timer);
var speed = target - alpha > 0 ? 10 : -10;
timer = setInterval(function () {
if(alpha == target){
clearInterval(timer);
} else {
alpha += speed;
oDiv1.style.opacity = alpha/100;
oDiv1.style.filter = "alpha(opacity: " + alpha + ")";
}
}, 30)
}
oDiv1.onmouseover = function () {
toggleShow(100);
}
oDiv1.onmouseout = function () {
toggleShow(30);
}
}
这里用了个小技巧:
由于透明度的设置方法有两种,不方便直接获取当前透明度的值,这里用了一个变量alpha
来保存透明度的值,alpha的初值设为30,跟css中设置的相同,而且增量是直接作用于alpha上的,最后才让透明度等于alpha的值
其他值得注意的是,参数target
是0-100的数值,所以最后oDiv1.style.opacity = alpha/100;
要除以100以恢复0-1的取值范围
以上。
转载请注明出处
网友评论