add custom solution for virtual scrolling to ease ram and cpu use when scrolling for a long time

This commit is contained in:
Shpuld Shpuldson 2020-01-15 15:17:05 +02:00
parent 7397636914
commit 9eae4d07c1
5 changed files with 57 additions and 9 deletions

View file

@ -35,7 +35,8 @@ const conversation = {
data () {
return {
highlight: null,
expanded: false
expanded: false,
height: '115px'
}
},
props: [
@ -44,7 +45,8 @@ const conversation = {
'isPage',
'pinnedStatusIdsObject',
'inProfile',
'profileUserId'
'profileUserId',
'hidden'
],
created () {
if (this.isPage) {
@ -102,6 +104,9 @@ const conversation = {
},
isExpanded () {
return this.expanded || this.isPage
},
hiderStyle () {
return this.hidden ? { height: this.height } : {}
}
},
components: {
@ -112,7 +117,7 @@ const conversation = {
const newConversationId = this.getConversationId(newVal)
const oldConversationId = this.getConversationId(oldVal)
if (newConversationId && oldConversationId && newConversationId === oldConversationId) {
this.setHighlight(this.originalStatusId)
this.setHighheightlight(this.originalStatusId)
} else {
this.fetchConversation()
}
@ -121,6 +126,10 @@ const conversation = {
if (value) {
this.fetchConversation()
}
},
hidden (value) {
this.height = `${this.$el.clientHeight}px`
console.log('Element height:', this.height)
}
},
methods: {

View file

@ -1,10 +1,11 @@
<template>
<div
:style="hiderStyle"
class="timeline panel-default"
:class="[isExpanded ? 'panel' : 'panel-disabled']"
>
<div
v-if="isExpanded"
v-if="isExpanded && !hidden"
class="panel-heading conversation-heading"
>
<span class="title"> {{ $t('timeline.conversation') }} </span>
@ -28,6 +29,7 @@
:replies="getReplies(status.id)"
:in-profile="inProfile"
:profile-user-id="profileUserId"
:hidden="hidden"
class="status-fadein panel-body"
@goto="setHighlight"
@toggleExpanded="toggleExpanded"

View file

@ -34,7 +34,8 @@ const Status = {
'inlineExpanded',
'showPinned',
'inProfile',
'profileUserId'
'profileUserId',
'hidden'
],
data () {
return {
@ -121,7 +122,7 @@ const Status = {
return this.mergedConfig.hideFilteredStatuses
},
hideStatus () {
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses)
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses) || this.hidden
},
isFocused () {
// retweet or root of an expanded conversation

View file

@ -32,7 +32,8 @@ const Timeline = {
return {
paused: false,
unfocused: false,
bottomedOut: false
bottomedOut: false,
vScrollIndex: 0
}
},
computed: {
@ -68,6 +69,12 @@ const Timeline = {
},
pinnedStatusIdsObject () {
return keyBy(this.pinnedStatusIds)
},
displayingStatuses () {
const amount = this.timeline.visibleStatuses.length
const min = Math.max(0, this.vScrollIndex - 20)
const max = Math.min(amount, this.vScrollIndex + 20)
return this.timeline.visibleStatuses.slice(min, max).map(_ => _.id)
}
},
components: {
@ -79,7 +86,7 @@ const Timeline = {
const credentials = store.state.users.currentUser.credentials
const showImmediately = this.timeline.visibleStatuses.length === 0
window.addEventListener('scroll', this.scrollLoad)
window.addEventListener('scroll', throttle(this.scrollLoad, 100))
if (store.state.api.fetchers[this.timelineName]) { return false }
@ -142,7 +149,35 @@ const Timeline = {
}
})
}, 1000, this),
determineVisibleStatuses () {
const statuses = this.$refs.timeline.children
const bodyBRect = document.body.getBoundingClientRect()
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
const centerOfScreen = window.pageYOffset + (window.innerHeight * 0.5)
// Approximate which status is in the middle of the screen and check how
// far it is roughly from the viewport
let approxIndex = Math.floor(statuses.length * (centerOfScreen / height))
let err = statuses[approxIndex].getBoundingClientRect().y
// if the status is too far from viewport, check the next/previous ones if
// they happen to be better
while (err < -100) {
approxIndex++
err = statuses[approxIndex].getBoundingClientRect().y
}
while (err > 1000) {
approxIndex--
err = statuses[approxIndex].getBoundingClientRect().y
}
// this status is now the center point for virtual scrolling
this.vScrollIndex = approxIndex
},
scrollLoad (e) {
this.determineVisibleStatuses()
const bodyBRect = document.body.getBoundingClientRect()
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
if (this.timeline.loading === false &&

View file

@ -34,7 +34,7 @@
</div>
</div>
<div :class="classes.body">
<div class="timeline">
<div ref="timeline" class="timeline">
<template v-for="statusId in pinnedStatusIds">
<conversation
v-if="timeline.statusesObject[statusId]"
@ -56,6 +56,7 @@
:collapsable="true"
:in-profile="inProfile"
:profile-user-id="userId"
:hidden="!displayingStatuses.includes(status.id)"
/>
</template>
</div>