JS运动
Posted lzn0330
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS运动相关的知识,希望对你有一定的参考价值。
新学的JS运动,和各位分享一下。
提到运动,肯定要对元素进行定位,通过更改它的left,top值来实现定位的目的,运动过程用定时器来实现。
基本步骤:
1.关闭上一个定时器(多次触发事件会开启多个定时器,会累加)
2.开启一个定时器
3.定义一个值作为运动的速度
4.判断定时器什么时候关闭,也就是终止条件
5.让元素怎样动
下面开始说几种常见的运动
1.匀速运动
速度是不变的。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{margin:0;padding:0;}
#box{
width: 100px;
height: 100px;
background: red;
position: absolute;
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
<script>
var oBox = document.getElementById("box");
var speed = 10;
var timer=null;
document.onclick = function () {
timer= setInterval(function(){
if(oBox.offsetLeft>=400){
clearInterval(timer);
}else{
oBox.style.left = oBox.offsetLeft+speed+"px";
}
},30)
}
</script>
oBox会匀速向右运动400px后停止,建议终止条件写oBox.offsetLeft>=400,而不是oBox.offsetLeft==400,因为定时器每次加一个speed,不一定正好加到所给的终止值。
以下案例的布局是一样的,所以只写JS代码
2.减速运动
<script>
var oBox = document.getElementById("box");
var speed = 40;
var timer=null;
document.onclick = function () {
timer= setInterval(function(){
speed--;
if(speed<0){
speed=0;
}
console.log();
if(oBox.offsetLeft>=800){
clearInterval(timer);
}else{
oBox.style.left = oBox.offsetLeft+speed+"px";
}
},30)
}
</script>
速度每次减减,加速度相同,所以是匀减速运动
3.匀加速运动(同理)
<script>
var oBox = document.getElementById("box");
var speed = 5;
var timer=null;
document.onclick = function () {
timer= setInterval(function(){
speed++;
if(speed>=40){
speed=40;
}
if(oBox.offsetLeft>=800){
clearInterval(timer);
}else{
oBox.style.left = oBox.offsetLeft+speed+"px";
}
},30)
}
</script>
4.缓冲运动 (样式改变)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{margin:0;padding:0;}
#box{
width: 100px;
height: 100px;
background: red;
position: absolute;
left: 800px;
}
#border{
width: 1px;
height: 300px;
background: #000;
position: absolute;
left: 400px;
top: 0;
}
</style>
</head>
<body>
<div id="box"></div>
<div id="border"></div>
</body>
</html>
<script>
var oBox = document.getElementById("box");
var timer = null;
document.onclick=function(){
clearInterval(timer);
timer=setInterval(function(){
var speed=(400-oBox.offsetLeft)/8;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
console.log(speed);
if(oBox.offsetLeft==400){
clearInterval(timer);
}else{
oBox.style.left=oBox.offsetLeft+speed+"px";
}
},30);
}
</script>
每次都把速度的值变小,但不是均匀的改变(跟减速运动最大不同),取整是为了让浏览器更好的计算,避免计算小数,以免出现误差。
封装一下。
function move(obj,iTarget){
clearInterval(timer);
timer = setInterval(function(){
//速度
var speed = (iTarget - obj.offsetLeft)/8;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
if(obj.offsetLeft==iTarget){
clearInterval(timer)
}else{
obj.style.left = obj.offsetLeft+speed+"px";
}
},30)
}
obj,是对象,iTarget是目标值。例如:move(div,400)
5.上面的封装不完善,想改变一个元素的透明度就做不到。透明度是小数且没单位,还得做IE的兼容,下面是怎样更改透明度
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{margin:0;padding:0;}
#box{
width: 100px;
height: 100px;
background: red;
opacity: 1;
filter: alpha(opacity: 100);
}
</style>
</head>
<body>
<div id="box"></div>
</body>
</html>
<script>
var oBox = document.getElementById("box");
var timer =null;
var alpha = 100;
document.onclick=function(){
clearInterval(timer);
timer=setInterval(function(){
var speed=(30-alpha)/8;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(alpha==30){
clearInterval(timer);
}else{
alpha+=speed;
oBox.style.opacity=alpha/100;
oBox.style.filter="alpha(opacity:"+alpha+")";
}
},30);
}
</script>
6.考虑到透明度,于是再次封装。
这次先封装一个获取非行内元素
function getStyle(obj,attr){
return obj.currentStyle?obj.currentStyle[attr]:getComputedStyle(obj,false)[attr];
}
function move(obj,target,attr){
clearInterval(timer);
timer=setInterval(function(){
var icur=0;
if(attr=="opacity"){
//避免opacity的值是0.5555555这样,所以取整
icur=parseInt(getStyle(obj,attr)*100);
}else{
icur=parseInt(getStyle(obj,attr));
}
var speed=(target-icur)/8;
speed=speed>0?Math.ceil(speed):Math.floor(speed);
if(icur==target){
clearInterval(timer);
}else{
if(attr=="opacity"){
obj.style.opacity=(icur+speed)/100;
obj.style.filter="alpha(opacity:"+(icur+speed)+")";
}else{
obj.style[attr]=icur+speed+"px";
}
}
},30);
}
oBox.onmouseover = function(){
move(this,100,"opacity");
}
调用一下,没问题
7.多物体运动框架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
*{margin:0;padding:0;}
div{
width: 100px;
height: 100px;
background: red;
opacity: 0.3;
filter: alpha(opacity: 30);
margin: 10px;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
</body>
</html>
<script>
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr];
}
}
function move(obj,iTarget,attr){
//obj.timer,定时器之间不影响
clearInterval(obj.timer);
obj.timer = setInterval(function(){
//第一步 判断attr是否为透明度
var iCur = 0;
if(attr == "opacity"){
iCur =parseInt(getStyle(obj,attr)*100);
}else{
iCur = parseInt(getStyle(obj,attr));
}
//第二步算速度
var speed = (iTarget - iCur )/8;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
//第三步
if(iCur == iTarget){
clearInterval(obj.timer);
}else{
if(attr == "opacity"){
obj.style.opacity = (iCur+speed)/100;
obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
}else{
obj.style[attr] = iCur+speed+"px";
}
}
},30)
}
var aDiv = document.getElementsByTagName("div");
aDiv[0].onmouseover = function(){
move(this,300,"width")
}
aDiv[1].onmouseover = function(){
move(this,300,"height")
}
aDiv[2].onmouseover = function(){
move(this,100,"opacity")
}
</script>
当多物体的时候,只用一个timer定义定时器时,会影响下一个物体的运动,所以要用obj.timer,关闭的时候关闭自己的定时器,不影响其他定时器的执行
8.链式运动
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr];
}
}
function move(obj,iTarget,attr,fn){
clearInterval(obj.timer);
obj.timer = setInterval(function(){
//第一步 判断attr是否为透明度
var iCur = 0;
if(attr == "opacity"){
iCur =parseInt(getStyle(obj,attr)*100);
}else{
iCur = parseInt(getStyle(obj,attr));
}
//第二步算速度
var speed = (iTarget - iCur )/8;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
//第三步
if(iCur == iTarget){
clearInterval(obj.timer);
fn&&fn();
}else{
if(attr == "opacity"){
obj.style.opacity = (iCur+speed)/100;
obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
}else{
obj.style[attr] = iCur+speed+"px";
}
}
},30)
}
var aDiv = document.getElementsByTagName("div");
aDiv[0].onmouseover = function(){
move(this,100,"opacity",function(){
move(aDiv[0],300,"height");
})
}
//给2个move(),下面会覆盖上面的函数,再写一个事件,也不行
aDiv[1].onmouseover = function(){
move(this,300,"height")
}
aDiv[2].onmouseover = function(){
move(this,100,"opacity")
}
给原来封装的函数加一个回调函数,解决
9.完美运动(让元素2个属性同时运动,链式运动只能一个执行完,再执行另一个)
<script>
function getStyle(obj,attr){
if(obj.currentStyle){
return obj.currentStyle[attr];
}else{
return getComputedStyle(obj,false)[attr];
}
}
//obj={width:100,height:200}
function move(obj,json,fn){
//防止多次点击 关闭掉上一个定时器
clearInterval(obj.timer);
//开启定时器 obj.timer:防止多个对象抢定时器
obj.timer = setInterval(function(){
//开关门
var bStop = true;
//传入的是一个对象 需要将对象中所有的值进行遍历
for(var attr in json){
/*
因为offset的局限性太大,如果想要这个方法灵活多用只能用获取非行间样式
考虑2点
1、透明度是小数 不能够直接取整需要先*100在取整
2、因为getStyle()获取出来的是字符串 我们需要将它转换为数字
*/
var iCur = 0;
if(attr == "opacity"){
iCur = parseInt(getStyle(obj,attr)*100);
}else{
iCur = parseInt(getStyle(obj,attr));
}
/*
因为要做缓存运动,因此需要计算速度 速度是一个不定值
公式: (目标值 - 当前对象的位置) /系数 建议是8
考虑的问题:
计算机处理小数有问题因此需要将小数干掉,我们要进行向上取整和向下取整
*/
//算速度
var speed = (json[attr] - iCur)/8;
speed = speed>0?Math.ceil(speed):Math.floor(speed);
/*判断是否都已经到达终点 只要有一个没有到达终点就将bStop为false 循环完毕以后判断bstop来决定关闭定时器*/
if(json[attr] !=iCur){
bStop = false;
}
/*
考虑2部分
1、透明度是不需要加px的因此需要单独判断
2、普通的属性是需要加px的因此需要再次判断
*/
if(attr == "opacity"){
//透明度的兼容性
obj.style.opacity = (iCur+speed)/100;
obj.style.filter = "alpha(opacity:"+(iCur+speed)+")";
}else{
obj.style[attr] = (iCur+speed)+"px";
}
}
//当循环完毕以后 判断bStop的状态来决定是否关闭定时器
if(bStop){
clearInterval(obj.timer);
//链式操作
fn&&fn();
}
},30)
}
var aDiv = document.getElementsByTagName("div");
aDiv[0].onmouseover = function(){
move(this,{width:300,height:150},function(){
move(aDiv[0],{opacity:100});
});
}
以上是关于JS运动的主要内容,如果未能解决你的问题,请参考以下文章