素肌にサスペンダー

個人的な備忘と日記

Vue.jsで、特定の要素が画面に表示されたら実行したい時に便利なvue-intersect

vue-intersectがシンプルで便利だったので、使い方をメモ。

こちらを参考にインストール

github.com

NPM

npm install vue-intersect --save

Yarn

yarn add vue-intersect

使い方

使いたいVueファイルに、importして、@enter=で表示した時に実行したいmethodsを定義する。

<template>
  <div id="app">
    <intersect @enter="hoge">
      <div>intersectタグに囲まれたこの要素を表示したら、hogeメソッドが実行される</div>
    </intersect>
  </div>
</template>

<script>
import Intersect from 'vue-intersect'

export default {
  name: 'app',
  components: {
    Intersect
  },
  methods: {
    hoge () {
      alert('表示された')
    }
  }
}
</script>

リストから初期10件アイテムを表示して、intersectが表示されたら5件ずつ表示するサンプル

よくある、スクロールしたら続きのアイテムが見れる動作をvue-intersectを使ってやってみた

<template>
  <div id="app">
    <ul class="lists">
      <li 
        class="list"
        v-for="list in displayLists"
        :key="list">{{ list }}</li>
    </ul>
    <intersect @enter="moreList">
      <div id="js-more-loading">Loading...</div>
    </intersect>
  </div>
</template>

<script>
import Intersect from 'vue-intersect'

export default {
  name: 'app',
  data () {
    return {
      // 元のアイテムリスト
      lists: [
        '1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22'
      ],
      // 画面に表示するリスト
      displayLists:[],
      // 画面に表示するリスト数
      listLimit: '',
      // 初期の画面に表示するリスト数
      listLimitDefault: 10,
      // ローディング時に追加するリスト数
      listLimitMore: 5,
      // ロードした回数
      listLimitIncrement: 1
    }
  },
  components: {
    Intersect
  },
  mounted () {
    // 初期10件表示
    this.listLimit = this.listLimitDefault
    for (let i = 0; i < this.listLimit; i++) {
      if (this.lists[i]) {
        this.displayLists.push(this.lists[i])
      }
    }
  },
  methods: {
    moreList () {
      setTimeout(function () {
        // ローディング要素を非表示に
        document.getElementById('js-more-loading').classList.add('is-loaded')

        // displayListsに、ロードしたリストを代入する
        let lists = []
        this.listLimit = this.listLimitDefault + (this.listLimitMore * this.listLimitIncrement)
        for (let i = 0; i < this.listLimit; i++) {
          if (this.lists[i]) {
            lists.push(this.lists[i])
          }
        }
        this.displayLists = lists

        // listLimitIncrementのインクリメント
        this.listLimitIncrement = this.listLimitIncrement + 1

        // ローディング要素を再表示
        document.getElementById('js-more-loading').classList.remove('is-loaded')

        // アイテムを表示し終わったら、ローディング要素を非表示にする
        if (this.lists.length - this.listLimitMore <= this.listLimitMore * this.listLimitIncrement) {
          document.getElementById('js-more-loading').classList.add('is-loaded')
          return
        }
      }.bind(this), 500)
    },
  }
}
</script>

<style>
.lists {
  min-height: 100vh;
}
.list {
  height: 20vh;
}
.is-loaded {
  display: none;
}
</style>

こんな感じになればOK vue-intersectでもっと見る

@enterだけでなく、@leaveや@changeで、見えなくなった時や状態変わった時も実行出来るので、アイデア次第で色々つかえそう https://github.com/heavyy/vue-intersect#events

IE11に対応する場合

intersection-observerのpolyfillの設定が必要。

www.npmjs.com

polyfill導入方法
  • npmインストール or scriptタグで導入する。
npm install intersection-observer

or

<script src="path/to/intersection-observer.js"></script>
  • import Intersect from 'vue-intersect'の上とかに追記する。
require('intersection-observer')