summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJohn Molakvoæ <skjnldsv@users.noreply.github.com>2019-03-27 11:06:22 +0100
committerGitHub <noreply@github.com>2019-03-27 11:06:22 +0100
commit273632613aa8a99f1dafb21820fe5c60550a0edc (patch)
tree39e7abde3bd927c9c1d29a0e86ec2a6fd6d53b17 /src
parent7d899726fd0bd14134dc2f936eb518e8f398c745 (diff)
parent201ed2ada952b5a587b33ecc4967f025fb2fe77a (diff)
Merge pull request #1018 from nextcloud/enhancement/perf/virtual-scroller
Use virtual scroller for big contacts list display performances
Diffstat (limited to 'src')
-rw-r--r--src/components/ContactDetails.vue14
-rw-r--r--src/components/ContactsList.vue78
2 files changed, 71 insertions, 21 deletions
diff --git a/src/components/ContactDetails.vue b/src/components/ContactDetails.vue
index 38533a01..f8b1c1e5 100644
--- a/src/components/ContactDetails.vue
+++ b/src/components/ContactDetails.vue
@@ -403,7 +403,7 @@ export default {
},
/**
- * Select a contac, and update the localContact
+ * Select a contact, and update the localContact
* Fetch updated data if necessary
* Scroll to the selected contact if exists
*
@@ -455,18 +455,6 @@ export default {
this.localContact = localContact
this.loadingData = false
}
-
- // scroll to selected contact if any
- let list = document.getElementById('contacts-list')
- let item = document.querySelector('#' + btoa(contact.key).slice(0, -2))
- if (item) {
- let isAbove = list.scrollTop > item.offsetTop
- let isUnder = item.offsetTop + item.offsetHeight > list.scrollTop + list.offsetHeight
- // check if contact outside visible list area
- if (isAbove || isUnder) {
- list.scrollTo(0, item.offsetTop - item.offsetHeight / 2)
- }
- }
}
},
diff --git a/src/components/ContactsList.vue b/src/components/ContactsList.vue
index e2475baf..c7bfcb08 100644
--- a/src/components/ContactsList.vue
+++ b/src/components/ContactsList.vue
@@ -21,23 +21,35 @@
-->
<template>
- <div id="contacts-list" :class="{'icon-loading': loading, showdetails: selectedContact}" class="app-content-list">
- <!-- same uid can coexists between different addressbooks
- so we need to use the addressbook id as key as well -->
- <contacts-list-item v-for="(contact, index) in list" :key="contact.key" :contact="contacts[contact.key]"
- :search-query="searchQuery" :list="list" :index="index"
- @deleted="selectContact" />
- </div>
+ <!-- same uid can coexists between different addressbooks
+ so we need to use the addressbook id as key as well -->
+ <recycle-scroller
+ id="contacts-list"
+ ref="scroller"
+ :class="{'icon-loading': loading, showdetails: selectedContact}"
+ class="app-content-list"
+ :items="list"
+ :item-size="itemHeight"
+ key-field="key">
+ <template v-slot="{ item, index }">
+ <contacts-list-item :key="item.key"
+ :contact="contacts[item.key]" :search-query="searchQuery" :index="index"
+ @deleted="selectContact" />
+ </template>
+ </recycle-scroller>
</template>
<script>
import ContactsListItem from './ContactsList/ContactsListItem'
+import { RecycleScroller } from 'vue-virtual-scroller/dist/vue-virtual-scroller.umd.js'
+import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
export default {
name: 'ContactsList',
components: {
- ContactsListItem
+ ContactsListItem,
+ RecycleScroller
},
props: {
@@ -59,6 +71,12 @@ export default {
}
},
+ data() {
+ return {
+ itemHeight: 68
+ }
+ },
+
computed: {
selectedContact() {
return this.$route.params.selectedContact
@@ -68,6 +86,24 @@ export default {
}
},
+ watch: {
+ selectedContact: function(key) {
+ this.$nextTick(() => {
+ this.scrollToContact(key)
+ })
+ },
+ list: function(val, old) {
+ // we just loaded the list and the url already have a selected contact
+ // if not, the selectedContact watcher will take over
+ // to select the first entry
+ if (val.length !== 0 && old.length === 0 && this.selectedContact) {
+ this.$nextTick(() => {
+ this.scrollToContact(this.selectedContact)
+ })
+ }
+ }
+ },
+
methods: {
// Select closest contact on deletion
selectContact(oldIndex) {
@@ -78,6 +114,32 @@ export default {
this.$router.push({ name: 'contact', params: { selectedGroup: this.selectedGroup, selectedContact: newContact.key } })
}
}
+ },
+
+ /**
+ * Scroll to the desired contact if in the list and not visible
+ *
+ * @param {String} key the contact unique key
+ */
+ scrollToContact(key) {
+ const item = this.$el.querySelector('#' + btoa(key).slice(0, -2))
+
+ // if the item is not visible in the list or barely visible
+ if (!(item && item.getBoundingClientRect().y > 50)) { // header height
+ const index = this.list.findIndex(contact => contact.key === key)
+ if (index > -1) {
+ this.$refs.scroller.scrollToItem(index)
+ }
+ }
+
+ // if item is a bit out (bottom) of the list, let's just scroll a bit to the top
+ if (item) {
+ const pos = item.getBoundingClientRect().y + this.itemHeight - (this.$el.offsetHeight + 50)
+ if (pos > 0) {
+ const scroller = this.$refs.scroller.$el
+ scroller.scrollTop = scroller.scrollTop + pos
+ }
+ }
}
}
}