On gists
Intersection observer (infinity scroll)
27.9.2022
•
2.10.2022 (aktualizováno)
JavaScript
Web Api
demo.js
Raw
#
// https://levelup.gitconnected.com/what-is-intersection-observer-api-and-how-is-it-useful-1e91a14579df
// https://codepen.io/ohdylan/pen/ZExqKzx
let secondLastChild = document.querySelectorAll('.box:nth-last-child(2)')[0];
let boxes = document.querySelector('.boxes')
const mockFetchMoreBoxes = () => {
const startIndex = parseInt(secondLastChild.textContent.replace('Test Element', '')) + 2
for(let i = startIndex; i < startIndex + 20; i++) {
const newBox = document.createElement('div')
newBox.textContent = `Test Element ${i}`
newBox.classList.add('box')
boxes.append(newBox)
if(i == startIndex + 18) {
observer.unobserve(secondLastChild)
secondLastChild = newBox
observer.observe(secondLastChild);
}
}
}
let observer = new IntersectionObserver((entries) => {
console.log(entries[0])
const secondLastChild = entries[0]
if(secondLastChild.isIntersecting){
return mockFetchMoreBoxes()
}
}, {})
observer.observe(secondLastChild);
demo.html
Raw
#
<div class="boxes">
<div class="box">Test Element 1</div>
<div class="box">Test Element 2</div>
<div class="box">Test Element 3</div>
<div class="box">Test Element 4</div>
<div class="box">Test Element 5</div>
<div class="box">Test Element 6</div>
<div class="box">Test Element 7</div>
<div class="box">Test Element 8</div>
<div class="box">Test Element 9</div>
<div class="box">Test Element 10</div>
<div class="box">Test Element 11</div>
<div class="box">Test Element 12</div>
<div class="box">Test Element 13</div>
<div class="box">Test Element 14</div>
<div class="box">Test Element 15</div>
<div class="box">Test Element 16</div>
</div>
demo2.js
Raw
#
// https://mayank-jain.medium.com/infinite-scrolling-using-vue3-and-intersectionobserver-e767c58c4bd3
// src/components/InfiniteScroller.vue
<script setup>
import { ref, onMounted } from "vue";
const emits = defineEmits(['infinite']);
let scroller = ref(null);
let endOfScroller = ref(null);
onMounted(() => {
const observer = new IntersectionObserver((entries) => {
let entry = entries[0];
if(entry.isIntersecting) {
emits('infinite');
}
}, { root: scroller.value });
observer.observe(endOfScroller.value);
});
</script>
<template>
<div ref="scroller" class="scroller">
<slot></slot>
<div ref="endOfScroller"></div>
</div>
</template>
<style scoped>
.scroller {
height: 100%;
width: 100%;
overflow: auto;
}
</style>
// src/components/Card.vue
<script setup>
defineProps({
value: Number,
});
</script>
<template>
<div class="card">{{ value }}</div>
</template>
<style scoped>
.card {
height: 10rem;
width: 10rem;
padding: 2rem;
color: white;
background-color: indigo;
display: flex;
justify-content: center;
align-items: center;
font-size: 3rem;
}
</style>
// src/components/ Cards.vue
<script setup>
import { ref } from "vue";
import Card from "./Card.vue";
import InfiniteScroller from "./InfiniteScroller.vue";
let items = ref([]);
let limit = 100;
let offset = 0;
const loadItems = async () => {
const newItems = await generateData(limit, offset);
items.value = [...items.value, ...newItems];
++offset;
};
const generateData = (limit, offset, delay = 1000) => {
return new Promise((resolve) => {
const newData = Array(limit)
.fill(0)
.map((_, index) => index + offset * limit + 1);
setTimeout(resolve, delay, newData);
});
};
</script>
<template>
<InfiniteScroller class="cards" @infinite="loadItems">
<Card v-for="item in items" :value="item" :key="item"></Card>
</InfiniteScroller>
</template>
<style scoped>
.cards {
display: flex;
gap: 1rem;
flex-wrap: wrap;
justify-content: center;
padding: 1rem;
box-sizing: border-box;
}
</style>