【问题标题】:Vue set up IntersectionObserverVue设置IntersectionObserver
【发布时间】:2017-12-21 10:00:01
【问题描述】:

我正在尝试为无限滚动列表设置一个 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>

要获取最后一个renderedDeal,我在交易中使用ref

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

这适用于初始设置并触发。问题是当我想要无限滚动时,我需要继续附加到交易列表中。所以我的lastRenderedDeal 会不断更新以反映附加到我列表中的最后一笔交易。

这种反应似乎没有传递给observer.observe 方法。它只拾取我的初始元素。这似乎很明显,因为它已在 mounted 挂钩中实例化,但我该如何处理呢?

我是否需要为交易设置观察者并再次调用observer.observe?如果是这样,我可以简单地告诉它替换最初的观察项吗?

【问题讨论】:

    标签: javascript vue.js vuejs2 vue-component intersection-observer


    【解决方案1】:

    您可以观察到一个虚拟的&lt;div&gt;,它始终位于列表的底部。您可能需要在 &lt;div&gt; 上设置 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 方法的观察者来更新观察者,如下所示:this.observer.observe(element); 但我更喜欢你的方法。它将无限滚动逻辑抽象为它自己的组件。喜欢它,谢谢你的帮助。
    • 还有一种方法可以避免 1px 高度样式;我尝试使用rootMargin,但它没有帮助(诚然,我并没有太努力,所以有人可能会建议修复它)。
    • 点赞!对不起,如果这是一个愚蠢的问题,我不明白发生了什么,如果你点击检查元素,节点的数量会不断增加,所以交叉点观察者在哪里回收内容,同时只保留几个节点
    • @PirateApp 这并不是一个虚拟列表;仅仅通过使用交叉点观察器,您不会免费获得虚拟化。 GitHub 上有虚拟化列表的实现,推荐你去看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-23
    • 2020-03-12
    • 1970-01-01
    • 2019-03-13
    • 2017-12-22
    • 2021-09-23
    相关资源
    最近更新 更多