Fix lazy loading skipping items

This commit is contained in:
Marco Realacci 2022-12-23 01:00:51 +01:00
parent 54453fea34
commit 0bd6f4461d
5 changed files with 69 additions and 57 deletions

View file

@ -0,0 +1,39 @@
<script>
export default {
name: 'IntersectionObserver',
props: {
sentinalName: {
type: String,
required: true,
},
},
data() {
return {
isIntersectingElement: false,
}
},
watch: {
isIntersectingElement: function (value) {
if (!value) return
this.$emit('on-intersection-element')
},
},
mounted() {
const sentinal = this.$refs[this.sentinalName]
const handler = (entries) => {
if (entries[0].isIntersecting) {
this.isIntersectingElement = true
}
else {
this.isIntersectingElement = false
}
}
const observer = new window.IntersectionObserver(handler)
observer.observe(sentinal)
},
}
</script>
<template>
<div :ref="sentinalName" class="w-full h-px relative" />
</template>

View file

@ -8,6 +8,7 @@ import LoadingSpinner from './components/LoadingSpinner.vue'
import PostCard from './components/PostCard.vue'
import UserCard from './components/UserCard.vue'
import Modal from './components/Modal.vue'
import IntersectionObserver from './components/IntersectionObserver.vue'
import 'bootstrap-icons/font/bootstrap-icons.css'
import './assets/dashboard.css'
@ -25,6 +26,7 @@ app.component("LoadingSpinner", LoadingSpinner);
app.component("PostCard", PostCard);
app.component("UserCard", UserCard);
app.component("Modal", Modal);
app.component("IntersectionObserver", IntersectionObserver);
app.use(router)
app.mount('#app')

View file

@ -38,21 +38,12 @@ export default {
this.loading = false;
},
loadMore() {
if (this.loading || this.data_ended) return
this.start_idx += this.limit
this.loadContent()
},
scroll() {
window.onscroll = () => {
let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight >= document.documentElement.offsetHeight - 5
if (bottomOfWindow && !this.data_ended) {
this.loadMore()
}
}
},
},
mounted() {
this.scroll();
this.refresh();
}
}
@ -86,6 +77,7 @@ export default {
<button v-if="(!data_ended && !loading)" @click="loadMore" class="btn btn-secondary py-1 mb-5"
style="border-radius: 15px">Load more</button>
<IntersectionObserver sentinal-name="load-more-home" @on-intersection-element="loadMore" />
</div>
</div>
</div>

View file

@ -1,88 +1,70 @@
<script>
import IntersectionObserver from '../components/IntersectionObserver.vue';
export default {
data: function () {
return {
requestedProfile: this.$route.params.user_id,
loading: false,
loading: true,
loadingError: false,
stream_data: [],
data_ended: false,
start_idx: 0,
limit: 1,
user_data: [],
}
};
},
methods: {
async refresh() {
this.getMainData();
// this way we are sure that we fill the first page todo: check
// 450 is a bit more of the max height of a post
// todo: may not work in 4k screens :/
this.limit = Math.max(Math.round(window.innerHeight / 450), 1)
this.limit = Math.max(Math.round(window.innerHeight / 450), 1);
this.start_idx = 0;
this.data_ended = false;
this.stream_data = [];
this.loadContent();
},
async getMainData() {
let response = await this.$axios.get("/users/" + this.requestedProfile);
if (response == null) {
this.loading = false
this.loadingError = true
return
this.loading = false;
this.loadingError = true;
return;
}
this.user_data = response.data;
},
async loadContent() {
this.loading = true;
let response = await this.$axios.get("/users/" + this.requestedProfile + "/photos" + "?start_index=" + this.start_idx + "&limit=" + this.limit);
if (response == null) {
// do something
return
return;
}
if (response.data.length == 0 || response.data.length < this.limit) this.data_ended = true;
if (response.data.length == 0 || response.data.length < this.limit)
this.data_ended = true;
this.stream_data = this.stream_data.concat(response.data);
this.loading = false;
console.log(this.stream_data);
},
loadMore() {
if (this.loading || this.data_ended) return
this.start_idx += this.limit
this.loadContent()
},
scroll() {
window.onscroll = () => {
let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight >= document.documentElement.offsetHeight - 5
if (bottomOfWindow && !this.data_ended) {
this.start_idx += this.limit
this.loadMore()
}
}
},
},
created() {
if (this.$route.params.user_id == "me") {
//this.$router.replace({ path: "/profile/" + }); (It's ok to not redirect, it's just a matter of taste)
this.requestedProfile = this.$currentSession();
} else {
}
else {
this.requestedProfile = this.$route.params.user_id;
}
this.scroll();
//this.scroll();
this.refresh();
}
},
components: { IntersectionObserver }
}
</script>
@ -128,6 +110,7 @@ export default {
<button v-if="(!data_ended && !loading)" @click="loadMore" class="btn btn-secondary py-1 mb-5"
style="border-radius: 15px">Load more</button>
<IntersectionObserver sentinal-name="load-more-profile" @on-intersection-element="loadMore" />
</div>
</div>
</div>

View file

@ -30,34 +30,29 @@ export default {
}
let response = await this.$axios.get("/users?query=" + this.fieldUsername + "&start_index=" + this.startIdx + "&limit=" + this.limit);
// Errors are handled by the interceptor, which shows a modal dialog to the user and returns a null response.
if (response == null) {
this.loading = false
return
}
if (response.data.length == 0) this.dataEnded = true;
else this.streamData = this.streamData.concat(response.data);
this.loading = false;
},
scroll() {
window.onscroll = () => {
let bottomOfWindow = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop) + window.innerHeight >= document.documentElement.offsetHeight - 5
if (bottomOfWindow && !this.dataEnded) {
this.startIdx += this.limit
this.loadContent()
}
}
loadMore() {
if (this.loading || this.dataEnded) return
this.startIdx += this.limit
this.loadContent()
},
},
mounted() {
// this way we are sure that we fill the first page
// 72 is a bit more of the max height of a card
// todo: may not work in 4k screens :/
this.limit = Math.round(window.innerHeight / 72);
this.scroll();
this.limit = Math.round(window.innerHeight / 72)
}
}
</script>
@ -84,6 +79,7 @@ export default {
</div>
<LoadingSpinner :loading="loading" /><br />
<IntersectionObserver sentinal-name="load-more-search" @on-intersection-element="loadMore" />
</div>
</div>
</div>