javascript - Vue set up IntersectionObserver - Stack Overflow

I am trying to set up an IntersectionObserver for an infinite scroll list. I want to check with the Int

I am trying to set up an IntersectionObserver for an infinite scroll list. I want to check with the IntersectionObserver if the last item of a list has been reached.

So far my IntersectionObserver setup looks like this:

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());
}

My list items are rendered like this:

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

To fetch the last renderedDeal I use the ref on the deals:

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

This works for the initial setup and it triggers. The problem is that when I want infinite scroll I need to keep appending to the list of deals. So my lastRenderedDeal constantly updates to reflect the last deal that was appended to my list.

This reactivity is not being passed on to the observer.observe method it seems. It only picks up my initial element. This seems kind of obvious since it has been instantiated in the mounted hook but how can I deal with this?

Do I need to set a watcher for the deals and call the observer.observe again? If so, can I simply tell it to replace the initial observed item?

I am trying to set up an IntersectionObserver for an infinite scroll list. I want to check with the IntersectionObserver if the last item of a list has been reached.

So far my IntersectionObserver setup looks like this:

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());
}

My list items are rendered like this:

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

To fetch the last renderedDeal I use the ref on the deals:

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

This works for the initial setup and it triggers. The problem is that when I want infinite scroll I need to keep appending to the list of deals. So my lastRenderedDeal constantly updates to reflect the last deal that was appended to my list.

This reactivity is not being passed on to the observer.observe method it seems. It only picks up my initial element. This seems kind of obvious since it has been instantiated in the mounted hook but how can I deal with this?

Do I need to set a watcher for the deals and call the observer.observe again? If so, can I simply tell it to replace the initial observed item?

Share Improve this question asked Dec 21, 2017 at 10:00 Stephan-vStephan-v 20.4k32 gold badges123 silver badges211 bronze badges
Add a ment  | 

1 Answer 1

Reset to default 5

You can observe a dummy <div> which is always at the bottom of the list. You might need to set a key on the <div> to ensure that Vue won't recreate the element during each render of the ponent.

I always like to make a general and reusable ponent which bundles this behavior. Here's my take:

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',
  ponents: {
    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./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>

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744904914a4600195.html

相关推荐

  • javascript - Vue set up IntersectionObserver - Stack Overflow

    I am trying to set up an IntersectionObserver for an infinite scroll list. I want to check with the Int

    1天前
    50

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信