2

無限スクロールリスト用のIntersectionObserverを設定しようとしています。リストの最後の項目に達した場合は、IntersectionObserverにチェックします。Vueセットアップ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()); 
} 

マイリスト項目は、次のようにレンダリングされています:私はrefを使用し、最後のrenderedDealをフェッチするには

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

これまでのところ、私のIntersectionObserverセットアップは、次のようになります価格:

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

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

この反応は、表示されるobserver.observe方法に渡されていません。それは私の最初の要素を取り上げるだけです。これはmountedフックでインスタンス化されているので、これは明らかですが、どうすれば対処できますか?

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

答えて

3

ダミー<div>は、常にリストの一番下に表示されます。 <div>keyを設定して、コンポーネントの各レンダリング中にVueがその要素を再作成しないようにする必要があります。

私はいつもこの動作をまとめた一般的で再利用可能なコンポーネントを作りたいと思っています。ここに私のテイクです:

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>
私のようなので、観察を更新し、 `$ nextTick`方法でウォッチャーを使用して、私の問題を修正しました

+0

:' this.observer.observe(要素); '私はあなたのアプローチがもっと好きです。無限のスクロールロジックをそれ自身のコンポーネントに抽象化します。それを愛してください、あなたの助けに感謝します。 –

+0

また、1ピクセルの高さスタイルを避ける方法もあります。私は['rootMargin'](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/rootMargin)で試してみましたが、それは助けになりません(確かに私はあまりにも頑張っていませんでした。誰かがそれについて修正案を提案できるかもしれない)。 –

関連する問題