2

無限スクロール リスト用に IntersectionObserver を設定しようとしています。リストの最後の項目に到達したかどうかを IntersectionObserver で確認したい。

これまでのところ、IntersectionObserverのセットアップは次のようになっています。

mounted() {
    const config = {
        treshold: 1
    };

    const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
            if (entry.intersectionRatio > 0) console.log(entry.target);
        });
    }, config);

    observer.observe(this.lastRenderedDeal());
}

私のリスト項目は次のようにレンダリングされます:

<deal :deal="deal"
      :key="index"
      ref="deals"
      v-for="(deal, index) in deals"
</deal>

最後のrenderDealを取得するには、取引でを使用しrefます。

lastRenderedDeal() {
    const deals = this.$refs.deals;
    return deals ? deals[deals.length - 1].$el : null;
}

これは初期設定で機能し、トリガーされます。問題は、無限スクロールが必要な場合、取引リストに追加し続ける必要があることです。そのlastRenderedDealため、リストに追加された最後の取引を反映するように常に更新しています。

observer.observeこの反応性は、メソッドに渡されていないようです。それは私の最初の要素だけを拾います。フックでインスタンス化されているため、これは明らかなように思えますmountedが、どうすればこれに対処できますか?

取引のウォッチャーを設定して、observer.observe を再度呼び出す必要がありますか? もしそうなら、最初に観察されたアイテムを置き換えるように単純に指示できますか?

4

1 に答える 1

5

<div>常にリストの一番下にあるダミーを観察できます。コンポーネントの各レンダリング中に Vue が要素を再作成しないようにするには、 keyonを設定する必要がある場合があります。<div>

私はいつも、この振る舞いをまとめた一般的で再利用可能なコンポーネントを作りたいと思っています。これが私の見解です:

const InfiniteScroll = {
  render(h) {
    return h('div', [
      ...this.$slots.default,

      // A dummy div at the bottom of the list which we will observe.
      // We must set a key on this element so that Vue reuses
      // the same element it initially created upon each rerender.
      h('div', {
        key: 'footer',
        ref: 'footer',
        style: {
          height: '1px'
        },
      }),
    ]);
  },

  mounted() {
    this.observer = new IntersectionObserver(entries => {
      // We only have one entry. Is it visible?
      if (entries[0].intersectionRatio > 0) {
        this.$emit('trigger');
      }
    });

    // Observe the dummy footer element
    this.observer.observe(this.$refs.footer);
  },
};

new Vue({
  el: '#app',
  components: {
    InfiniteScroll,
  },
  data: {
    items: [],
  },
  created() {
    this.loadMore();
  },
  methods: {
    loadMore() {
      for (let i = 0; i < 20; i++) {
        this.items.push(this.items.length + 1);
      }
    },
  },
});
body {
  margin: 0;
}

.item {
  border-bottom: 1px solid #eee;
  padding: 10px;
}
<script src="https://rawgit.com/vuejs/vue/dev/dist/vue.js"></script>

<div id="app">
  <infinite-scroll @trigger="loadMore">
    <div v-for="item of items" class="item">{{ item }}</div>
  </infinite-scroll>
</div>

于 2017-12-21T11:02:03.523 に答える