GeekFactory

int128.hatenablog.com

vue.jsでInfinite Scrollを実装する

ページを下端までスクロールしたら次のページが読み込まれるInfinite Scroll(無限スクロール)をvue.jsで実装する方法を調べてみました.

一般的なInfinite Scrollの実装方法

スクロール可能な要素の scroll イベントを捕捉して,表示領域の位置を計算します.もし,要素の高さに達している場合は,下端までスクロールされたことになります.

<div class="items"></div>
.items {
  position: fixed;
  top: 0;
  bottom: 0;
  overflow-y: auto;
}
$('.items').on('scroll', function (e) {
  // jQueryを使う場合
  var target = $(e.target);
  if ((target.scrollTop() + target.outerHeight()) >= e.target.scrollHeight) {
    console.info('下端までスクロールされたよ');
  }

  // 標準APIのみを使う場合(IEは動かないかも)
  if ((e.target.scrollTop + e.target.offsetHeight) >= e.target.scrollHeight) {
    console.info('下端までスクロールされたよ');
  }
});

参考:javascript - How can I use JQuery to check if a div is scrolled all the way to the bottom? - Stack Overflow

vue.jsの実装方法

基本的なアイディアは上記と同じです.

<div class="items" v-on="scroll: scroll"></div>
new Vue({
  el: 'body',
  methods: {
    scroll: function (e) {
      if ((e.target.scrollTop + e.target.offsetHeight) >= e.target.scrollHeight) {
        console.info('下端までスクロールされたよ');
      }
    }
  }
});

なお,スクロール可能な要素と操作したいコンポーネントが入れ子になっている場合はイベントを使うときれいに書けます.下記のように,親コンポーネント$broadcast を叩いてイベントをブロードキャストして,子コンポーネント$on で受け取ります.

<div class="items" v-on="scroll: scroll">
  <div v-component="child"></div>
</div>
new Vue({
  el: 'body',
  methods: {
    scroll: function (e) {
      if ((e.target.scrollTop + e.target.offsetHeight) >= e.target.scrollHeight) {
        this.$broadcast('scroll-items-bottom');
      }
    }
  },
  components: {
    child: {
      template: 'child-template',
      created: function () {
        this.$on('scroll-items-bottom', function() {
          console.info('下端までスクロールされたよ');
        });
      }
    }
  }
});

まとめ

vue.jsでInfinite Scrollを実装する方法を説明しました.

ここで説明した方法は Evernote風のGistクライアント でも採用しています.

ところで,無限スクロールという名称ですが,最後のページにたどり着いたらスクロールが止まるので実は有限スクロールなのでは.まあFacebookTwitterなら本当に無限になりそうですね.