Although it is said to be a spring effect, what is actually achieved is acceleration and deceleration movement between fixed point coordinates.
You should know how to do point-to-point movement, here it is achieved by setting the left of the sliding object.
As for the deceleration effect, the general approach is to obtain a step size by dividing the target value minus the current value by a coefficient (usually a positive integer).
Then the current value is added to this step size as the new current value, and then the value is repeatedly taken until the current value is equal to the target value.
Since the step size obtained in this way is getting smaller and smaller, and the step size is the value of movement, it creates a deceleration effect.
How to create acceleration effect?
Since I can’t get the acceleration step size that can correspond to the deceleration step size (or there is a method that I can’t think of), so I thought of a method.
First calculate all the deceleration step sizes and put them into one In the array, as the step size during deceleration, the step size for acceleration is the inversion of the array (that is, upside down).
This part is mainly in the SetStep() function, please refer to the code.
Other parts are explained in the code.
Program code:
Code
var $ = function (id) {
return "string" == typeof id ? document.getElementById(id) : id;
};
function addEventHandler(oTarget, sEventType, fnHandler) {
if (oTarget.addEventListener) {
oTarget.addEventListener(sEventType, fnHandler, false);
} else if (oTarget.attachEvent) {
oTarget.attachEvent("on" sEventType, fnHandler);
} else {
oTarget["on" sEventType] = fnHandler;
}
};
var Class = {
create: function() {
return function() {
this.initialize.apply(this, arguments);
}
}
}
Object.extend = function(destination, source) {
for (var property in source) {
destination[property] = source[property];
}
return destination;
}
var Bounce = Class.create();
Bounce.prototype = {
//容器对象,滑动对象,原始位置,移动范围
initialize: function(container, obj, iOrigin, iRange, options) {
this._obj = $(obj);//滑动对象
this._xo = parseInt(iOrigin);//中轴坐标(即原来坐标)
this._xt = 0;//目标坐标
this._xs = [];//目标坐标集合
this._steps = [];//步长集合
this._fast = true;//是否加速
this.Range = iRange || 0;//滑动范围(宽度)
this.SetOptions(options);
this.Step = parseInt(this.options.Step);
this.Time = parseInt(this.options.Time);
this.Zoom = parseInt(this.options.Zoom);
this.Reduce = !!this.options.Reduce;
this.Min = parseInt(this.options.Min);
this.Max = parseInt(this.options.Max);
this.onMin = this.options.onMin;
this.onMax = this.options.onMax;
this.onSide = this.options.onSide;
//样式设置
$(container).style.position = "relative";
this._obj.style.position = "absolute";
this._obj.style.left = this._xo "px";
if(this.Range > 0) this.Start();
},
//设置默认属性
SetOptions: function(options) {
this.options = {//默认值
Step: 10,//滑动变化率
Time: 10,//滑动延时
Zoom: 0,//缩放变化率
Reduce: true,//是否缩小
Min: 0,//最小范围
Max: 0,//最大范围
onMin: function(){},//到达最小时执行
onMax: function(){},//到达最大时执行
onSide: function(){}//到达边界时执行
};
Object.extend(this.options, options || {});
},
//从轴点开始
Start: function(iRange) {
clearTimeout(this._timer);
//iRange有值的话重新设置滑动范围
if(iRange) this.Range = iRange;
//是否到了最小点
if(this.Reduce && (this.Range <= 0 || this.Range <= this.Min)) { this.onMin(); return; }
//是否到了最大点
if(!this.Reduce && (this.Max > 0 && this.Range >= this.Max)) { this.onMax(); return; }
//重置位置
this._obj.style.left = this._xo "px";
//设置目标坐标集合(iRange可能会变化所以每次都要设置)
this._xs = [this._xo this.Range, this._xo, this._xo - this.Range, this._xo];
//设置为加速状态
this._fast = false;
//开始分段移动
this.Set();
},
//从分段开始
Set: function() {
//目标坐标都到达后返回
if(this._xs.length <= 0){
//缩放变化率有值的话重新设置范围
if(this.Zoom > 0) { this.Range = (this.Reduce ? -1 : 1) * this.Zoom; }
this.Start(); return;
}
//取得目标坐标
this._xt = this._xs.shift();
//目标坐标是中轴点说明现在是在边界上
if(this._xt == this._xo) this.onSide();
//设置步长
this.SetStep();
//开始移动
this.Move();
},
//移动
Move: function() {
clearTimeout(this._timer);
//步长走完即到达目标坐标就返回
if (this._steps.length <= 0) { this.Set(); return; }
//执行移动
this._obj.style.left = (parseInt(this._obj.style.left) this._steps.shift()) "px";
//循环移动
var oThis = this; this._timer = setTimeout(function(){ oThis.Move(); }, this.Time);
},
//设置步长
SetStep: function() {
var iTemp = parseInt(this._obj.style.left);
//注意是从大到小排的
this._steps = [];
if(this.Step >= 1){
var i = 0;
do{
i = (this._xt - iTemp) / this.Step;
//步长不能包含0
if (i == 0) { break; } else if (Math.abs(i) < 1) { i = i > 0 ? 1 : -1; }
this._steps.push(i = parseInt(i));
iTemp = i;
} while (true);
//如果是加速的话反转步长集合
if(this._fast) this._steps.reverse();
}
//加速减速是交替进行的所以每次都要取反
this._fast = !this._fast;
}
};
测试html:
测试代码:
new Bounce("idContainer", "idBounce", 250, 200);
var o = new Bounce("idContainer1", "idBounce1", 250, 200, {
Zoom: 20, Max: 200,
onMax: function(){ o.Reduce = true; o.Start(200); },
onMin: function(){ o.Reduce = false; o.Start(0); }
});
var o2 = new Bounce("idContainer2", "idBounce2", 250);
$("bb").onclick = function(){ o2.Start(parseInt($("aa").value) || 200); }
$("idFast").onclick = function(){ if(--o2.Step<2){o2.Step=2} }
$("idSlow").onclick = function(){ if( o2.Step>20){o2.Step=20} }
$("idZoom").onclick = function(){ o2.Zoom=50; }