js 弹簧效果代码

  虽然说的是弹簧效果,但实际上要实现的是定点坐标之间的加速和减速移动。

  点到点的移动应该都知道怎么做,这里是通过设置滑动对象的left来实现的。

  而减速效果,一般的做法是通过用目标值减当前值除以一个系数(一般为正整数),得到一个步长。

  然后当前值加上这个步长作为新的当前值,然后反复取值直到当前值等于目标值。

  由于这样得到的步长是越来越小的,而步长就是移动的值,所以就做成减速效果。

  那如何做加速效果呢?

  由于取不到能对应减速步长的加速的步长(或者有方法我想不到),所以我想了个方法,

  一开始先把所有减速的步长算出来,放到一个数组中,作为减速时的步长,那加速的步长就是这个数组的反转了(即倒过来)。

  这个部分主要在SetStep()函数中,可参照代码。

  其他部分在代码中都有说明。

  程序代码:

  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:

  

复制代码 代码如下:

  <style type="text/css">

  .container{border:1px solid #000000;height:50px; width:500px;}

  .bounce{width:10px; height:10px; background:#000000;top:20px;}

  </style>

  固定范围反弹:

  <div id="idContainer" class="container">

  <div id="idBounce" class="bounce"> </div>

  </div>

  <br />

  范围渐变反弹:

  <div id="idContainer1" class="container">

  <div id="idBounce1" class="bounce"> </div>

  </div>

  <br />

  自定范围反弹:

  <div id="idContainer2" class="container">

  <div id="idBounce2" class="bounce"> </div>

  </div>

  <br />

  范围:

  <input id="aa" name="" type="text" value="200" size="8" />

  <input id="bb" name="" type="button" value=" 开始 " />

  <input id="idFast" name="" type="button" value=" 加速 + " />

  <input id="idSlow" name="" type="button" value=" 减速 - " />

  <input id="idZoom" name="" type="button" value=" 渐 小 " />

  测试代码:

  

复制代码 代码如下:

  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; }

  

   [Ctrl+A 全选 注:如需引入外部Js需刷新才能执行]