👌

スクロール量を1回だけ取得するロジックのテスト

2022/12/01に公開
const getPosition = () => {
  const scrollTop = window.pageYOffset;
  offsetTop = el.getBoundingClientRect().top + scrollTop;
  endPosition = offsetTop + el.clientHeight;
  winHeight = window.innerHeight;
}
getPosition();
window.addEventListener('resize', getPosition);

先日公開した記事について
https://zenn.dev/icchicw/articles/4430a798efbf83

ScrollFunctionクラス内でGetPositionをインスタンス化して実行すると、オブザーバー領域に入った要素毎にスクロール量を取得してしまう。
本来であれば1回だけ取得すればいい。

1回だけ取得するにはオブザーバー領域にあるインスタンスの最後の要素がスクロール量を取得すれば良いのではないかと考えた。

以下はスクロール量を1回だけ取得するロジックのテストとして記載する。
なお頭の中で考えただけなので、まだ未検証である。

実際に検証したところ、if文で領域内にある最後のインスタンスでのみscrollTopを取るので、他のインスタンスに関して領域内にあってもアニメーションしない(scrollTopを取れてないので)
よって、このロジックは間違いでした。。

このクソコードはここで供養します🙏

class GetPosition {
  constructor() {
    
  }
  
  getScrollTop() {
    return window.pageYOffset;
  }
}

//それぞれのインスタンスがオブザーバー領域にあるか判別するための配列
let sfFlgs = [];

new ScrollFunction(".js-01", 500, "-30%", "10%", "80%", sfFlgs);
new ScrollFunction(".js-02", 500, "-30%", "10%", "80%", sfFlgs);
new ScrollFunction(".js-03", 500, "-30%", "10%", "80%", sfFlgs);

class ScrollFunction {
  static Count = 0; //インスタンス化の個数初期値
  constructor(target, scrollMax, rootMargin, Min, Max, fps = 60, sfFlgs) {
    ...
    this.sfFlgs = sfFlgs;
    this.sfCount = ScrollFunctionAll.Count;
    this.sfFlgs[this.sfCount] = false; //flgs配列にfalseを代入しておく
    ScrollFunctionAll.Count += 1; //個数+1

    this.scrollAnimation();
  }

  _scrollFunction() {
    ...
    const gp = new GetPosition();
    ...
    let scrollTop;
    let trueNum = 0; //flgsのtrueの数

    const scrollAnime = (timestamp) => {

      //flgs配列のアイテムがtrueならtrueNumに加算する
      for(let i = 0; i < this.sfFlgs.length; i++) {
        if(this.sfFlgs[i]) {
          trueNum += 1;
	}
      }
      
      //flgsアイテムが1つのみでtrue
      if(this.sfFlgs[0] && this.sfFlgs.length == 1) {
        scrollTop = gp.getScrollTop();
      } else { //flgsアイテム2つ目以降について
        //trueかつflgs配列のtrueの数が1つ(オブザーバー領域に1つのアイテムしか存在しない)
        if(this.sfFlgs[this.sfCount] && trueNum == 1) {
	  scrollTop = gp.getScrollTop();
	  
	//trueかつflgs配列のtrueの数が2つ以上(オブザーバー領域に複数存在)かつ最後の要素
        } else if(this.sfFlgs[this.sfCount] && trueNum > 1 && this.sfCount == (this.sfFlgs.length - 1)) {
	  scrollTop = gp.getScrollTop();
	}
      }
      trueNum = 0; //初期化
      
      if (isVisible) {
         frameId = requestAnimationFrame(scrollAnime);
       }
     }
     frameId = requestAnimationFrame(scrollAnime);
      
     const observer = new IntersectionObserver(entries => {
       entries.forEach(entry => {
         isVisible = entry.isIntersecting;
         if (isVisible) {
	   this.sfFlgs[this.sfCount] = true;
           frameId = requestAnimationFrame(scrollAnime);
         } else {
	   this.sfFlgs[this.sfCount] = false;
           //画面外のときは削除
           cancelAnimationFrame(frameId);
         }
       });
     });
     //observer監視開始
     observer.observe(el);
   });
  }
}

Discussion