JavaScript - 完美运动框架

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yb642518034/article/details/52083874

第一版运动框架

该框架通过妙味课堂学习视频时候跟着封装的。如下所示

function startMove(obj,json,endFn){
	clearInterval(obj.timer);
	obj.timer = setInterval(function(){
		var bBtn = true;
		for(var attr in json){
			var iCur = 0;
			if(attr == 'opacity'){
				if(Math.round(parseFloat(getStyle(obj,attr))*100)==0){
				iCur = Math.round(parseFloat(getStyle(obj,attr))*100);
				}
				else{
					iCur = Math.round(parseFloat(getStyle(obj,attr))*100) || 100;
				}	
			}
			else{
				iCur = parseInt(getStyle(obj,attr)) || 0;
			}
			
			var iSpeed = (json[attr] - iCur)/8;
			iSpeed = iSpeed >0 ? Math.ceil(iSpeed) : Math.floor(iSpeed);
			if(iCur!=json[attr]){
				bBtn = false;
			}
			if(attr == 'opacity'){
				obj.style.filter = 'alpha(opacity=' +(iCur + iSpeed)+ ')';
				obj.style.opacity = (iCur + iSpeed)/100;
			}
			else{
				obj.style[attr] = iCur + iSpeed + 'px';
			}
		}
		
		if(bBtn){
			clearInterval(obj.timer);
			if(endFn){
				endFn.call(obj);
			}
		}
	},30);
}
function getStyle(obj,attr){
	if(obj.currentStyle){
		return obj.currentStyle[attr];
	}
	else{
		return getComputedStyle(obj,false)[attr];
	}
}

但是该框架存在一个问题:由于现代浏览器为了提高性能,当页面处于不可见的状态时候,浏览器会减少调用次数,具体表现为当定时时间小于1s时,浏览器在后台会1s调用一次。这个是目前测试出来的,具体是多少时间调用一次尚不明确,但是可以肯定的是不会少于800ms。

第二版运动框架

下面的实现方法是依据tween.js插件实现的方案。通过时间计算偏移量,这样即使定时器执行时间被浏览器篡改,也能通过时间进行补偿,最终运动到目标位置

//运动对象,属性,持续时间,运动方式,回调函数
function startMove(obj, attrs, duration, fx, callback) {
	clearInterval(obj.timer);
	var startTime = new Date();
	var j = {};
	for (var attr in attrs) {
		j[attr] = {};
		//计算初始值
		if (attr == 'opacity') {
			j[attr].b = Math.round(getStyle(obj, attr) * 100);
		} else {
			j[attr].b = parseInt(getStyle(obj, attr));
		}
		//计算初始值与目标值的差值
		j[attr].c = attrs[attr] - j[attr].b;
	}
	var d = duration;
	obj.timer = setInterval(function() {
		var t = new Date() - startTime;
		//当第一进入方法的时间与当前时间差值大于动画的执行时间,停止定时器。
		if (t >= d) {
			t = d;
			clearInterval(obj.timer);
		}
		for (var attr in attrs) {
			var curValue = Tween[fx](t, j[attr].b, j[attr].c, d);
			if (attr == 'opacity') {
				obj.style.opacity = curValue / 100;
				obj.style.filter = 'alpha(opacity=' + curValue + ')';
			} else {
				obj.style[attr] = curValue + 'px';
			}
		}
		if (t == d) {
			callback && callback();
		}
	}, 15);
}
function getStyle(obj, attr) {
	if (obj.currentStyle) {
		return obj.currentStyle[attr];
	} else {
		return getComputedStyle(obj, false)[attr];
	}
}

对tween.js算法简单剖析


针对运动中用到的tween.js中的easeOut减速曲线做简单分析。由于fraction是一个时间差跟运动时间的比值,所以范围就是从0-1,时间t进行归一化处理也是从0-1

1、黑线部分公式fraction = - t * t

2、粉红色部分公式fraction = - t * t + 1;

3、红色部分公式fraction = - (t - 1) * (t - 1) + 1=- t * t + 2t

对于运动时间为d的过程讲,那么公式就是 - (t / d) * (t / d) + 2t = -(t/=d) * t + 2t = - (t/=d)(t-2);

所以最终的公式就是 -c(t/=d)(t-2) + b; 其中c就是从初始位置到结束位置的变化量。b就是初始位置。纵观整个公式的意思就是根据实际运动时间与计划运动时间的比值,然后乘上初始位置到结束为止的差值,在加上初始位置的值,就是要运动到的位置。由于fraction最大值为1,所以始终可以运动到结束位置,而不会出现小数造成的误差。

如果想要实现更多的运动效果,跟我公式计算即可。要注意曲线纵坐标的值最后一定为1,因为曲线得总体趋势一定是上升的!


这个是我的推导过程,如果有更好的方法,请指导!

展开阅读全文

没有更多推荐了,返回首页