mirror of
https://github.com/notherealmarco/WASAPhoto.git
synced 2025-03-13 13:35:23 +01:00
Fix lazy loading skipping items
This commit is contained in:
parent
54453fea34
commit
0bd6f4461d
5 changed files with 69 additions and 57 deletions
39
webui/src/components/IntersectionObserver.vue
Normal file
39
webui/src/components/IntersectionObserver.vue
Normal 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>
|
|
@ -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')
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue