2
0
mirror of https://github.com/tenrok/vue-select.git synced 2026-06-10 07:52:23 +03:00

feat: add open & close events (#1101)

This commit is contained in:
Jeff Sagal
2020-03-12 20:46:08 -07:00
committed by GitHub
parent bb3f28478f
commit e6d0da6d52
4 changed files with 100 additions and 0 deletions
@@ -0,0 +1,72 @@
<template>
<v-select
:options="paginated"
:filterable="false"
@open="onOpen"
@close="onClose"
@search="query => search = query"
ref="select"
>
<template #list-footer v-if="hasNextPage">
<li ref="load" class="loader">
Loading more options...
</li>
</template>
</v-select>
</template>
<script>
import countries from '../data/countries';
import vSelect from '../../../src/components/Select'
export default {
name: "InfiniteScroll",
components: {vSelect},
data: () => ({
observer: null,
limit: 10,
search: ''
}),
computed: {
filtered () {
return countries.filter(country => country.includes(this.search));
},
paginated () {
return this.filtered.slice(0, this.limit);
},
hasNextPage () {
return this.paginated.length + 10 < this.filtered.length;
},
},
mounted () {
this.observer = new IntersectionObserver(this.infiniteScroll);
},
methods: {
async onOpen () {
if (this.hasNextPage) {
await this.$nextTick();
this.observer.observe(this.$refs.load)
}
},
onClose () {
this.observer.disconnect();
},
async infiniteScroll ([{isIntersecting, target}]) {
if (isIntersecting) {
const ul = target.offsetParent;
const scrollTop = target.offsetParent.scrollTop;
this.limit += 10;
await this.$nextTick();
ul.scrollTop = scrollTop;
}
}
}
}
</script>
<style scoped>
.loader {
text-align: center;
color: #bbbbbb;
}
</style>
+1
View File
@@ -120,6 +120,7 @@ module.exports = {
['guide/validation', 'Validation'],
['guide/selectable', 'Limiting Selections'],
['guide/pagination', 'Pagination'],
['guide/infinite-scroll', 'Infinite Scroll'],
['guide/vuex', 'Vuex'],
['guide/ajax', 'AJAX'],
['guide/loops', 'Using in Loops'],
+23
View File
@@ -0,0 +1,23 @@
Vue Select doesn't ship with first party support for infinite scroll, but it's possible to implement
by hooking into the `open`, `close`, and `search` events, along with the `filterable` prop, and the
`list-footer` slot.
Let's break down the example below, starting with the `data`.
- `observer` - when the component is mounted, a new `IntersectionObserver` will be set here
- `limit` - the number of options to display 'per page'
- `search` - since we've disabled Vue Selects filtering, we'll need to filter options ourselves
When Vue Select opens, the `open` event is emitted and `onOpen` will be called. We wait for
`$nextTick()` so that the `$ref` we need will exist, then begin observing it for intersection.
The observer is set to call `infiniteScroll` when the `<li>` is completely visible within the list.
Some fancy destructuring is done here to get the first `ObservedEntry`, and specifically the
`isIntersecting` & `target` properties. If the `<li>` is intersecting, we increase the `limit`, and
ensure that the scroll position remains where it was before the list size changed. Again, it's
important to wait for `$nextTick` here so that the DOM elements have been inserted before setting
the scroll position.
<InfiniteScroll />
<<< @/.vuepress/components/InfiniteScroll.vue
+4
View File
@@ -619,6 +619,10 @@
*/
multiple() {
this.clearSelection()
},
open(isOpen) {
this.$emit(isOpen ? 'open' : 'close');
}
},