div要素などをスクロールに追随させるJavaScriptの続きです。

クラス化と、間違いや、効率的でないところの修正もしています。

サンプル(スクリプト以外は前回と同じ)

とりあえず隠蔽する

これでグローバル変数は2つになる。 でも、この場合、ScrollChaserのプロパティにはアクセスできない。

function ScrollChaser(id,int)
{
  var el;
  var initTop;
  var interval = int;
  //
  function setting()
  {
    el = document.getElementById(id);
    el.style.position = 'absolute';
    initTop = el.offsetTop;
    //
    try {
      window.addEventListener('scroll', scrollEvent, false);
    } catch (e) {
      window.attachEvent('onscroll',scrollEvent);
    }
  }
  function scrollEvent()
  {
    var myInt = setInterval(function()
      {
        var cur = (document.body.scrollTop||document.documentElement.scrollTop)+20;
        var myTop = el.offsetTop;
        var d = cur-myTop;
        if(Math.abs(d) > 1) {
          if( cur < = initTop )
          {
            var y = myTop + d/3;
            el.style.top = y+"px";
          } else {
            el.style.top = initTop+"px";
            clearInterval(myInt);
          }
        } else {
          el.style.top = cur+"px";
          clearInterval(myInt);
        }
      },interval);
  }
  try {
    window.addEventListener('load', setting, false);
  } catch (e) {
    window.attachEvent('onload', setting);
  }
}
//
var sc = new ScrollChaser('side',200);

prototypeプロパティを使用する

prototypeプロパティはnew演算子でオブジェクトが生成されたときに設定されます。 prototypeプロパティに追加されたプロパティはそのオブジェクトの全てのインスタンスで使うことができます。これによりクラス的なオブジェクトの使い方ができるようになります。

prototypeプロパティによりScrollChaser内のプロパティにアクセスできるようになりました。ただ、注意しないといけないのは、window.onloadsetInterval()からプロパティを呼び出すときにスコープを指定しないと呼び先のthisがオブジェクト本体を参照しなくなる(windowだとグローバルオブジェクトを参照することになるのかな?)ところ。ローカル変数にthisを格納してローカル変数を参照しなければなりません。

インスタンスプロパティ(this.hogehoge)にいちいちthisキーワードを指定しないといけないのは面倒いな。上記のようなActionScript的な書き方ができればいいのに。

function ScrollChaser(id,int)
{
  this.interval = int;
  this.id = id;
}
//
ScrollChaser.prototype.init = function()
{
  var scope = this;
  //
  try {
    window.addEventListener('load', scope.setting, false);
  } catch (e) {
    window.attachEvent('onload', scope.setting);
  }
}
ScrollChaser.prototype.setting = function()
{
  var scope = this;
  //
  this.el = document.getElementById(this.id);
  this.el.style.position = 'absolute';
  this.initTop = this.el.offsetTop;
  //
  try {
    window.addEventListener('scroll', scope.scrollEvent, false);
  } catch (e) {
    window.attachEvent('onscroll', scope.scrollEvent);
  }
}
ScrollChaser.prototype.scrollEvent = function()
{
  var el = this.el;
  var init = this.initTop;
  //
  var myInt = setInterval(function()
    {
      var cur = (document.body.scrollTop||document.documentElement.scrollTop)+20;
      var myTop = el.offsetTop;
      var d = cur-myTop;
      if(Math.abs(d)>1) {
        if( cur >= init )
        {
          var y = myTop + d/3;
          el.style.top = y+"px";
        } else {
          el.style.top = init+"px";
          clearInterval(myInt);
        }
      } else {
        el.style.top = cur+"px";
        clearInterval(myInt);
      }
    },this.interval);
}
//
var sc = new ScrollChaser('side',200);
sc.init();