Vue 设置 IntersectionObserver
Vue set up IntersectionObserver
我正在尝试为无限滚动列表设置 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?如果是这样,我可以简单地告诉它替换最初观察到的项目吗?
您可以观察到始终位于列表底部的虚拟 <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>
我正在尝试为无限滚动列表设置 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?如果是这样,我可以简单地告诉它替换最初观察到的项目吗?
您可以观察到始终位于列表底部的虚拟 <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>