VueJSでメモリマネジメントを加味した無限スクロールを実装

updated: 2021/7/18

 

無限スクロールは読み込むほどDOMが大きくなるので画面外のDOMは極力消して軽量化する必要がある。

 

より簡単な方法があったので加筆

vuetify の intersection-observer ディレクティブを使うと楽

 

環境:

vue@2.6.12

vuetify@2.5.6

vue-infinite-loading@2.4.5

 

参考:

vuetifyjs.com

developers.google.com

github.com

 

New Way)

 wrapper  v-intersect=onItersect

  v-card v-if="visible"

  mock v-else

 

onIntersect (entries, observer) {
  this.visible = entries[0].isIntersecting
},

 

wrapperとなるエレメントで v-intersect するだけでDOM消しを実装できる

下記方法のviewport の計算等は不要

 

注意)

ページを遷移させたときに無限スクロールの該当list の値を変化させると結局再計算コストが大きくかかるのでlistの値はページ遷移しても保持する

 

 

 

 

 

 

以下old way

 

方針1

listからviewportに表示されている部分をcomputedで抽出し、viewport外に空エレメントを挿入

>>> うまく滑らかな表示ができなかった

 

方針2

画面外に出たらv-ifで消し、v-elseで空エレメントを挿入。

 

f:id:monteecristoo:20210218030100p:plain

兄弟コンポーネント間で同一のメソッド(getCurrentDistance)をコールする方法は下記参照

monteecristoo.hatenablog.com

 

コンポーネント

 

data() {

  return {

    scrollWatcher: 0,

    initScrollPassive: false

  }

}

created() {

  window.addEventListner('scroll', this.detectScroll)

}

methods: {

  detectScroll() {

    this.scrollWatcher = 1

    // スクロールするたびにgetCurrentDistanceすると過剰にメソッドをコールするので頻度を調整

    if(!this.initScrollPassive) {

      this.initScrollPassive = true

      clearTimeout(this.passiveScrollStatus())

    }

  },

  passiveScrollStatus() {

    setTimeout(() => {

      this.scrollPassive = false

      this.scrollWatcher = 0

    }, 300)

  }

 

コンポーネント

<template>

  <div id="targetElement">

    <div v-if=visible>

      // list rendering content

    </div>

    <div v-else>

      // empty element

    </div>

  </div>

</template>

 

props: ['scrollWatcher']

data() {

  return {

    el: '',

    visible: true,

    viewportHeight: ''

  }

}

created() {

    this.el = doscument.getElementById("targetElement")

    this.viewportHeight = window.innerHeight

}

watch() {

  'scrollWatcher'() {

    if(this.scrollWatcher) {

      this.getCurrentDistance()

    }

  }

},

methods: {

f:id:monteecristoo:20210218044025p:plain

}

 

Need Fix

scrollWatcher の値が変化したときすべての子コンポーネントでgetCurrentDistaneを処理する必要無く、viewport 周辺のコンポーネントのみコールすればよい.

スクロール速度によってはviewport上に空エレメントを表示した状態で処理が止まってしまうことがあるのでスクロールイベントの取得法を見直す必要あり。