2022-04-15 14:24:30 +00:00
|
|
|
import { defineAsyncComponent, ref } from 'vue'
|
|
|
|
|
|
|
|
/**
|
2022-04-15 17:00:08 +00:00
|
|
|
* Add an "infinite scroll" functionality to any component using this mixin.
|
2022-04-15 14:24:30 +00:00
|
|
|
* Such a component should have a `scrolling` method bound to `scroll` event on
|
|
|
|
* the wrapper element: @scroll="scrolling"
|
|
|
|
*/
|
|
|
|
export const useInfiniteScroll = (perPage: number = 30) => {
|
|
|
|
const ToTopButton = defineAsyncComponent(() => import('@/components/ui/to-top-button.vue'))
|
|
|
|
|
2022-04-15 17:00:08 +00:00
|
|
|
const scroller = ref(null as unknown as HTMLElement)
|
2022-04-15 14:24:30 +00:00
|
|
|
const displayedItemCount = ref(perPage)
|
|
|
|
|
2022-04-15 17:00:08 +00:00
|
|
|
const displayMore = () => (displayedItemCount.value += perPage)
|
2022-04-15 14:24:30 +00:00
|
|
|
|
|
|
|
const scrolling = (target: HTMLElement) => {
|
|
|
|
// Here we check if the user has scrolled to the end of the wrapper (or 32px to the end).
|
|
|
|
// If that's true, load more items.
|
|
|
|
if (target.scrollTop + target.clientHeight >= target.scrollHeight - 32) {
|
|
|
|
displayMore()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-15 17:00:08 +00:00
|
|
|
const makeScrollable = (totalItemCount: number) => {
|
|
|
|
const container = scroller.value!
|
2022-04-15 14:24:30 +00:00
|
|
|
if (container.scrollHeight <= container.clientHeight && displayedItemCount.value < totalItemCount) {
|
|
|
|
displayMore()
|
2022-04-15 17:00:08 +00:00
|
|
|
// we can't use $nextTick here because it's instant and scrollHeight wouldn't have been updated.
|
|
|
|
window.setTimeout(() => makeScrollable(totalItemCount), 200)
|
2022-04-15 14:24:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
ToTopButton,
|
|
|
|
displayedItemCount,
|
2022-04-15 17:00:08 +00:00
|
|
|
scroller,
|
2022-04-15 14:24:30 +00:00
|
|
|
scrolling,
|
|
|
|
makeScrollable
|
|
|
|
}
|
|
|
|
}
|