add custom solution for virtual scrolling to ease ram and cpu use when scrolling for a long time
This commit is contained in:
parent
7397636914
commit
9eae4d07c1
5 changed files with 57 additions and 9 deletions
|
@ -35,7 +35,8 @@ const conversation = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
highlight: null,
|
highlight: null,
|
||||||
expanded: false
|
expanded: false,
|
||||||
|
height: '115px'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: [
|
props: [
|
||||||
|
@ -44,7 +45,8 @@ const conversation = {
|
||||||
'isPage',
|
'isPage',
|
||||||
'pinnedStatusIdsObject',
|
'pinnedStatusIdsObject',
|
||||||
'inProfile',
|
'inProfile',
|
||||||
'profileUserId'
|
'profileUserId',
|
||||||
|
'hidden'
|
||||||
],
|
],
|
||||||
created () {
|
created () {
|
||||||
if (this.isPage) {
|
if (this.isPage) {
|
||||||
|
@ -102,6 +104,9 @@ const conversation = {
|
||||||
},
|
},
|
||||||
isExpanded () {
|
isExpanded () {
|
||||||
return this.expanded || this.isPage
|
return this.expanded || this.isPage
|
||||||
|
},
|
||||||
|
hiderStyle () {
|
||||||
|
return this.hidden ? { height: this.height } : {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -112,7 +117,7 @@ const conversation = {
|
||||||
const newConversationId = this.getConversationId(newVal)
|
const newConversationId = this.getConversationId(newVal)
|
||||||
const oldConversationId = this.getConversationId(oldVal)
|
const oldConversationId = this.getConversationId(oldVal)
|
||||||
if (newConversationId && oldConversationId && newConversationId === oldConversationId) {
|
if (newConversationId && oldConversationId && newConversationId === oldConversationId) {
|
||||||
this.setHighlight(this.originalStatusId)
|
this.setHighheightlight(this.originalStatusId)
|
||||||
} else {
|
} else {
|
||||||
this.fetchConversation()
|
this.fetchConversation()
|
||||||
}
|
}
|
||||||
|
@ -121,6 +126,10 @@ const conversation = {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.fetchConversation()
|
this.fetchConversation()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
hidden (value) {
|
||||||
|
this.height = `${this.$el.clientHeight}px`
|
||||||
|
console.log('Element height:', this.height)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
|
:style="hiderStyle"
|
||||||
class="timeline panel-default"
|
class="timeline panel-default"
|
||||||
:class="[isExpanded ? 'panel' : 'panel-disabled']"
|
:class="[isExpanded ? 'panel' : 'panel-disabled']"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="isExpanded"
|
v-if="isExpanded && !hidden"
|
||||||
class="panel-heading conversation-heading"
|
class="panel-heading conversation-heading"
|
||||||
>
|
>
|
||||||
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
<span class="title"> {{ $t('timeline.conversation') }} </span>
|
||||||
|
@ -28,6 +29,7 @@
|
||||||
:replies="getReplies(status.id)"
|
:replies="getReplies(status.id)"
|
||||||
:in-profile="inProfile"
|
:in-profile="inProfile"
|
||||||
:profile-user-id="profileUserId"
|
:profile-user-id="profileUserId"
|
||||||
|
:hidden="hidden"
|
||||||
class="status-fadein panel-body"
|
class="status-fadein panel-body"
|
||||||
@goto="setHighlight"
|
@goto="setHighlight"
|
||||||
@toggleExpanded="toggleExpanded"
|
@toggleExpanded="toggleExpanded"
|
||||||
|
|
|
@ -34,7 +34,8 @@ const Status = {
|
||||||
'inlineExpanded',
|
'inlineExpanded',
|
||||||
'showPinned',
|
'showPinned',
|
||||||
'inProfile',
|
'inProfile',
|
||||||
'profileUserId'
|
'profileUserId',
|
||||||
|
'hidden'
|
||||||
],
|
],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
@ -121,7 +122,7 @@ const Status = {
|
||||||
return this.mergedConfig.hideFilteredStatuses
|
return this.mergedConfig.hideFilteredStatuses
|
||||||
},
|
},
|
||||||
hideStatus () {
|
hideStatus () {
|
||||||
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses)
|
return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses) || this.hidden
|
||||||
},
|
},
|
||||||
isFocused () {
|
isFocused () {
|
||||||
// retweet or root of an expanded conversation
|
// retweet or root of an expanded conversation
|
||||||
|
|
|
@ -32,7 +32,8 @@ const Timeline = {
|
||||||
return {
|
return {
|
||||||
paused: false,
|
paused: false,
|
||||||
unfocused: false,
|
unfocused: false,
|
||||||
bottomedOut: false
|
bottomedOut: false,
|
||||||
|
vScrollIndex: 0
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -68,6 +69,12 @@ const Timeline = {
|
||||||
},
|
},
|
||||||
pinnedStatusIdsObject () {
|
pinnedStatusIdsObject () {
|
||||||
return keyBy(this.pinnedStatusIds)
|
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: {
|
components: {
|
||||||
|
@ -79,7 +86,7 @@ const Timeline = {
|
||||||
const credentials = store.state.users.currentUser.credentials
|
const credentials = store.state.users.currentUser.credentials
|
||||||
const showImmediately = this.timeline.visibleStatuses.length === 0
|
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 }
|
if (store.state.api.fetchers[this.timelineName]) { return false }
|
||||||
|
|
||||||
|
@ -142,7 +149,35 @@ const Timeline = {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}, 1000, this),
|
}, 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) {
|
scrollLoad (e) {
|
||||||
|
this.determineVisibleStatuses()
|
||||||
const bodyBRect = document.body.getBoundingClientRect()
|
const bodyBRect = document.body.getBoundingClientRect()
|
||||||
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
|
const height = Math.max(bodyBRect.height, -(bodyBRect.y))
|
||||||
if (this.timeline.loading === false &&
|
if (this.timeline.loading === false &&
|
||||||
|
|
|
@ -34,7 +34,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div :class="classes.body">
|
<div :class="classes.body">
|
||||||
<div class="timeline">
|
<div ref="timeline" class="timeline">
|
||||||
<template v-for="statusId in pinnedStatusIds">
|
<template v-for="statusId in pinnedStatusIds">
|
||||||
<conversation
|
<conversation
|
||||||
v-if="timeline.statusesObject[statusId]"
|
v-if="timeline.statusesObject[statusId]"
|
||||||
|
@ -56,6 +56,7 @@
|
||||||
:collapsable="true"
|
:collapsable="true"
|
||||||
:in-profile="inProfile"
|
:in-profile="inProfile"
|
||||||
:profile-user-id="userId"
|
:profile-user-id="userId"
|
||||||
|
:hidden="!displayingStatuses.includes(status.id)"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue