JavaScript 物体的运动

最近学习了物体的运动框架,觉得有必要做下总结!

1. 匀速运动

首先准备一个div,css样式如下:

			#div1 {
				width: 200px;
				height: 200px;
				background: red;
				position: absolute;
				left: 0;
				top: 0;
			}

  接下来,我们让这个div动起来

function startMove(obj, iTarget) {
                clearInterval(obj.timer);  //防止重复开启定时器
                obj.timer = setInterval(function() {
                    var speed = obj.offsetLeft < iTarget ? 10 : -10;  //判断速度的正负
                    if (obj.offsetLeft == iTarget) {
                        clearInterval(obj.timer);  //达到目标,关闭定时器
                    } else {
                        obj.style.left = obj.offsetLeft + speed + 'px';
                    }
                }, 30);
            }

  div每30毫秒向右运动10px,当div.style.left等于iTarget的时候,停下来,这段代码看似没有问题。其实当速度设置 7 的时候,问题就出来了。当div.style.left增加到 399的时候,再增加一个7 就变成 406了,div发现多了6, 就会减7 ,发现又少了……反反复复,div.style.left就是到不了目标位置,div也就停不下来了。

  修改代码,注意红色代码:

            function startMove2(obj, iTarget) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    var speed = obj.offsetLeft < iTarget ? 7 : -7;
                    if (Math.abs(obj.offsetLeft - iTarget) <= speed) {
                        clearInterval(obj.timer);
                        obj.style.left = iTarget + 'px';
                    } else {
                        obj.style.left = obj.offsetLeft + speed + 'px';
                    }
                }, 30);
            }

这样,不管速度设置是多少,都能停下来。

2. 变速运动

变速运动关键在于速度不是一个定值,它一般随着距离的减小而减小,换句话说,距离目标大的时候速度快,距离目标小的时候速度慢。

如何做到这一点呢? 将目标值与当前值相减的差值 除以 一个数(这个数的大小由你决定),这样速度就在不断变化。具体看代码:

 1             function startMove3(obj, iTarget) {
 2                 clearInterval(timer);
 3                 timer = setInterval(function() {
 4                     var speed = (iTarget - obj.offsetHeight) / 10;
 5                  
 6                     if (obj.offsetHeight == iTarget) {
 7                         clearInterval(timer);
 8                     } else {
 9                         obj.style.height = obj.offsetHeight + speed + 'px';
10                     }
11                 }, 30);
12             }

同样也是存在问题的。最后速度会变成零点几,一个小数,但css能分辨的最小单位是1px,零点几的px都默认是0,因此物体会在目标值前面一小段距离停止不动,尽管定时器还没满足关闭的条件,但是速度已经为0,每次都是加零,所以停止不动了。

改进代码:

            function startMove3(obj, iTarget) {
                clearInterval(timer);
                timer = setInterval(function() {
                    var speed = (iTarget - obj.offsetHeight) / 10;
                    speed = obj.offsetHeight < iTarget ? Math.ceil(speed) : Math.floor(speed);
                    if (obj.offsetHeight == iTarget) {
                        clearInterval(timer);
                    } else {
                        obj.style.height = obj.offsetHeight + speed + 'px';
                    }
                }, 30);
            }

 3. 函数的改进

  以上函数都有一个确定,将改变的属性设死了,要么只能变化高度或宽度。我们可以再加入一个 attribute 参数 ,使得函数更加灵活。

  改进代码:

            function startMove(obj, attribute, iTarget) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    var cur = parseInt(getStyle(obj, attribute));
                    var speed = (iTarget - cur) / 6;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    if (cur == iTarget) {
                        clearInterval(obj.timer);
                    } else {
                        obj.style[attribute] = cur + speed + 'px';
                    }
                }, 30);
            }
            //获取元素的CSS属性
            function getStyle(obj, name) {
                if (obj.currentStyle) {
                    return obj.currentStyle[name];
                } else {
                    return getComputedStyle(obj, false)[name];
                }
            }

  其中,getStyle(obj,name)是一个获取css属性的函数。

  这个运动函数目前只能针对属性值含有px的,因此我们还需要多一条判断满足透明度改变的需求。

  改进2:

            function startMove(obj, attribute, iTarget) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    var cur = attribute == 'opacity' ? Math.round(parseFloat(getStyle(obj, attribute) * 100)) : parseInt(getStyle(obj, attribute));
                    var speed = (iTarget - cur) / 6;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    if (cur == iTarget) {
                        clearInterval(obj.timer);
                    } else {
                        if (attribute == 'opacity') {
                            obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";  //针对IE
                            obj.style.opacity = (cur + speed) / 100;  //针对FireFox Chrome
                        } else {
                            obj.style[attribute] = cur + speed + 'px';
                        }
                    }
                }, 30);
            }

  代码中 Math.round(parseFloat(getStyle(obj, attribute) * 100))  对 opacity 数值的处理 , 由于不同浏览器对小数取舍不一样,使用Math.round() 进行四舍五入 , 这样有的浏览器不会出现透明度到达目标值后闪了。

4. 链式运动 

            function startMove(obj, attribute, iTarget ,fnEnd) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    var cur = attribute == 'opacity' ? Math.round(parseFloat(getStyle(obj, attribute) * 100)) : parseInt(getStyle(obj, attribute));
                    var speed = (iTarget - cur) / 6;
                    speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                    if (cur == iTarget) {
                        clearInterval(obj.timer);
                        if(fnEnd){
                            fnEnd();
                        }
                    } else {
                        if (attribute == 'opacity') {
                            obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                            obj.style.opacity = (cur + speed) / 100;
                        } else {
                            obj.style[attribute] = cur + speed + 'px';
                        }
                    }
                }, 30);
            }

5. 多值多属性同时运动

  引入一个json {width : target1,height:target2,opacity:target3}.

function startMove(obj, json, fnEnd) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    for (var attr in json) {
                        var cur = attr == 'opacity' ? Math.round(parseFloat(getStyle(obj, attr) * 100)) : parseInt(getStyle(obj, attr));
                        var speed = (json[attr] - cur) / 6;
                        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                        if (cur == json[attr]) {
                            clearInterval(obj.timer);
                            if (fnEnd) {
                                fnEnd();
                            }
                        } else {
                            if (attr == 'opacity') {
                                obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                                obj.style.opacity = (cur + speed) / 100;
                            } else {
                                obj.style[attr] = cur + speed + 'px';
                            }
                        }
                    }
                }, 30);
            }

  如果多个属性目标值不一致,定时器启动的时候,目标值小的属性会先满足了关闭定时器的条件,而目标值大的属性还没有到达目标,因此会产生偏差。

  改进代码(最终完美版运动代码):

function startMove(obj, json, fnEnd) {
                clearInterval(obj.timer);
                obj.timer = setInterval(function() {
                    var bStop = true;
                    for (var attr in json) {
                        var cur = attr == 'opacity' ? Math.round(parseFloat(getStyle(obj, attr) * 100)) : parseInt(getStyle(obj, attr));
                        var speed = (json[attr] - cur) / 6;
                        speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
                        if (cur != json[attr]) {
                            bStop = false;
                        }
                        if (attr == 'opacity') {
                            obj.style.filter = "alpha(opacity:" + (cur + speed) + ")";
                            obj.style.opacity = (cur + speed) / 100;
                        } else {
                            obj.style[attr] = cur + speed + 'px';
                        }
                    }
                    if(bStop){
                        clearInterval(obj.timer);
                        if(fnEnd){
                            fnEnd();
                        }
                    }
                }, 30);
            }

 

转载于:https://www.cnblogs.com/dontStopByTime/p/5509183.html

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值