Use virtual scrolling for emoji picker
This commit is contained in:
parent
d0c7ceb584
commit
afd7f5fabe
6 changed files with 83 additions and 58 deletions
|
@ -45,6 +45,7 @@
|
|||
"vue-i18n": "9.2.2",
|
||||
"vue-router": "4.1.6",
|
||||
"vue-template-compiler": "2.7.14",
|
||||
"vue-virtual-scroller": "^2.0.0-beta.7",
|
||||
"vuex": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createRouter, createWebHistory } from 'vue-router'
|
||||
import vClickOutside from 'click-outside-vue3'
|
||||
import VueVirtualScroller from 'vue-virtual-scroller'
|
||||
import 'vue-virtual-scroller/dist/vue-virtual-scroller.css'
|
||||
|
||||
import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome'
|
||||
|
||||
|
@ -397,6 +399,7 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
|||
|
||||
app.use(vClickOutside)
|
||||
app.use(VBodyScrollLock)
|
||||
app.use(VueVirtualScroller)
|
||||
|
||||
app.component('FAIcon', FontAwesomeIcon)
|
||||
app.component('FALayers', FontAwesomeLayers)
|
||||
|
|
|
@ -143,22 +143,13 @@ const EmojiPicker = {
|
|||
}
|
||||
this.$emit('emoji', { insertion: value, keepOpen: this.keepOpen })
|
||||
},
|
||||
onScroll (e) {
|
||||
const target = (e && e.target) || this.$refs['emoji-groups']
|
||||
this.updateScrolledClass(target)
|
||||
this.scrolledGroup(target)
|
||||
onScroll (startIndex, endIndex, visibleStartIndex, visibleEndIndex) {
|
||||
const current = this.filteredEmojiGroups[visibleStartIndex].id
|
||||
this.scrolledGroup(current)
|
||||
},
|
||||
scrolledGroup (target) {
|
||||
const top = target.scrollTop + 5
|
||||
this.$nextTick(() => {
|
||||
this.allEmojiGroups.forEach(group => {
|
||||
const ref = this.groupRefs['group-' + group.id]
|
||||
if (ref && ref.offsetTop <= top) {
|
||||
this.activeGroup = group.id
|
||||
}
|
||||
})
|
||||
this.scrollHeader()
|
||||
})
|
||||
scrolledGroup (groupId) {
|
||||
this.activeGroup = groupId
|
||||
this.scrollHeader()
|
||||
},
|
||||
scrollHeader () {
|
||||
// Scroll the active tab's header into view
|
||||
|
@ -177,14 +168,9 @@ const EmojiPicker = {
|
|||
setScroll(right + margin - headerCont.clientWidth)
|
||||
}
|
||||
},
|
||||
highlight (key) {
|
||||
const ref = this.groupRefs['group-' + key]
|
||||
const top = ref.offsetTop
|
||||
highlight (index) {
|
||||
this.setShowStickers(false)
|
||||
this.activeGroup = key
|
||||
this.$nextTick(() => {
|
||||
this.$refs['emoji-groups'].scrollTop = top + 1
|
||||
})
|
||||
this.$refs['emoji-groups'].scrollToItem(index)
|
||||
},
|
||||
updateScrolledClass (target) {
|
||||
if (target.scrollTop <= 5) {
|
||||
|
@ -238,6 +224,9 @@ const EmojiPicker = {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
minItemSize () {
|
||||
return 32
|
||||
},
|
||||
activeGroupView () {
|
||||
return this.showingStickers ? '' : this.activeGroup
|
||||
},
|
||||
|
|
|
@ -74,6 +74,7 @@ $emoji-picker-emoji-size: 32px;
|
|||
}
|
||||
|
||||
.emoji-groups {
|
||||
height: 100%;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
class="emoji-tabs"
|
||||
>
|
||||
<span
|
||||
v-for="group in filteredEmojiGroups"
|
||||
v-for="(group, index) in filteredEmojiGroups"
|
||||
:ref="setGroupRef('group-header-' + group.id)"
|
||||
:key="group.id"
|
||||
class="emoji-tabs-item"
|
||||
|
@ -21,7 +21,7 @@
|
|||
active: activeGroupView === group.id
|
||||
}"
|
||||
:title="group.text"
|
||||
@click.prevent="highlight(group.id)"
|
||||
@click.prevent="highlight(index)"
|
||||
>
|
||||
<span
|
||||
v-if="group.image"
|
||||
|
@ -74,45 +74,52 @@
|
|||
@input="$event.target.composing = false"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
<DynamicScroller
|
||||
ref="emoji-groups"
|
||||
class="emoji-groups"
|
||||
:class="groupsScrolledClass"
|
||||
@scroll="onScroll"
|
||||
:min-item-size="minItemSize"
|
||||
:items="filteredEmojiGroups"
|
||||
@update="onScroll"
|
||||
>
|
||||
<div
|
||||
v-for="group in filteredEmojiGroups"
|
||||
:key="group.id"
|
||||
class="emoji-group"
|
||||
>
|
||||
<h6
|
||||
:ref="setGroupRef('group-' + group.id)"
|
||||
class="emoji-group-title"
|
||||
<template #default="{ item: group, index, active }">
|
||||
<DynamicScrollerItem
|
||||
:item="group"
|
||||
:active="active"
|
||||
:data-index="index"
|
||||
:size-dependencies="[group.emojis.length]"
|
||||
>
|
||||
{{ group.text }}
|
||||
</h6>
|
||||
<span
|
||||
v-for="emoji in group.emojis"
|
||||
:key="group.id + emoji.displayText"
|
||||
:title="maybeLocalizedEmojiName(emoji)"
|
||||
class="emoji-item"
|
||||
@click.stop.prevent="onEmoji(emoji)"
|
||||
>
|
||||
<span
|
||||
v-if="!emoji.imageUrl"
|
||||
class="emoji-picker-emoji -unicode"
|
||||
>{{ emoji.replacement }}</span>
|
||||
<still-image
|
||||
v-else
|
||||
class="emoji-picker-emoji -custom"
|
||||
loading="lazy"
|
||||
:src="emoji.imageUrl"
|
||||
:data-emoji-name="group.id + emoji.displayText"
|
||||
/>
|
||||
</span>
|
||||
<span :ref="setGroupRef('group-end-' + group.id)" />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="emoji-group"
|
||||
>
|
||||
<h6
|
||||
class="emoji-group-title"
|
||||
>
|
||||
{{ group.text }}
|
||||
</h6>
|
||||
<span
|
||||
v-for="emoji in group.emojis"
|
||||
:key="group.id + emoji.displayText"
|
||||
:title="maybeLocalizedEmojiName(emoji)"
|
||||
class="emoji-item"
|
||||
@click.stop.prevent="onEmoji(emoji)"
|
||||
>
|
||||
<span
|
||||
v-if="!emoji.imageUrl"
|
||||
class="emoji-picker-emoji -unicode"
|
||||
>{{ emoji.replacement }}</span>
|
||||
<still-image
|
||||
v-else
|
||||
class="emoji-picker-emoji -custom"
|
||||
loading="lazy"
|
||||
:src="emoji.imageUrl"
|
||||
:data-emoji-name="group.id + emoji.displayText"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</DynamicScrollerItem>
|
||||
</template>
|
||||
</DynamicScroller>
|
||||
<div class="keep-open">
|
||||
<Checkbox v-model="keepOpen">
|
||||
{{ $t('emoji.keep_open') }}
|
||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -6370,6 +6370,11 @@ minimist@^1.2.5:
|
|||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
|
||||
integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
|
||||
|
||||
mitt@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/mitt/-/mitt-2.1.0.tgz#f740577c23176c6205b121b2973514eade1b2230"
|
||||
integrity sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==
|
||||
|
||||
mkdirp@^0.5.1:
|
||||
version "0.5.1"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
|
||||
|
@ -8805,6 +8810,16 @@ vue-loader@17.0.1:
|
|||
hash-sum "^2.0.0"
|
||||
loader-utils "^2.0.0"
|
||||
|
||||
vue-observe-visibility@^2.0.0-alpha.1:
|
||||
version "2.0.0-alpha.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-observe-visibility/-/vue-observe-visibility-2.0.0-alpha.1.tgz#1e4eda7b12562161d58984b7e0dea676d83bdb13"
|
||||
integrity sha512-flFbp/gs9pZniXR6fans8smv1kDScJ8RS7rEpMjhVabiKeq7Qz3D9+eGsypncjfIyyU84saU88XZ0zjbD6Gq/g==
|
||||
|
||||
vue-resize@^2.0.0-alpha.1:
|
||||
version "2.0.0-alpha.1"
|
||||
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-2.0.0-alpha.1.tgz#43eeb79e74febe932b9b20c5c57e0ebc14e2df3a"
|
||||
integrity sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==
|
||||
|
||||
vue-router@4.1.6:
|
||||
version "4.1.6"
|
||||
resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.6.tgz#b70303737e12b4814578d21d68d21618469375a1"
|
||||
|
@ -8828,6 +8843,15 @@ vue-template-compiler@2.7.14:
|
|||
de-indent "^1.0.2"
|
||||
he "^1.2.0"
|
||||
|
||||
vue-virtual-scroller@^2.0.0-beta.7:
|
||||
version "2.0.0-beta.7"
|
||||
resolved "https://registry.yarnpkg.com/vue-virtual-scroller/-/vue-virtual-scroller-2.0.0-beta.7.tgz#4ea8158638c84b2033b001a8b26c5fcb6896b271"
|
||||
integrity sha512-OrouVj1i2939jaLjVfu8f5fsDlbzhAb4bOsYZYrAkpcVLylAmMoGtIL7eT3hJrdTiaKbwQpRdnv7DKf9Fn+tHg==
|
||||
dependencies:
|
||||
mitt "^2.1.0"
|
||||
vue-observe-visibility "^2.0.0-alpha.1"
|
||||
vue-resize "^2.0.0-alpha.1"
|
||||
|
||||
vue@3.2.45:
|
||||
version "3.2.45"
|
||||
resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.45.tgz#94a116784447eb7dbd892167784619fef379b3c8"
|
||||
|
|
Loading…
Reference in a new issue