koel/resources/assets/js/composables/useInfiniteScroll.ts

41 lines
1.3 KiB
TypeScript
Raw Normal View History

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"
*/
2022-04-21 21:51:17 +00:00
export const useInfiniteScroll = (perPage = 30) => {
const ToTopButton = defineAsyncComponent(() => import('@/components/ui/ScrollToTopButton.vue'))
2022-04-15 14:24:30 +00:00
2022-04-21 21:51:17 +00:00
const scroller = ref<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
2022-04-21 21:51:17 +00:00
const scrolling = ({ target }: { target: HTMLElement }) => {
2022-04-15 14:24:30 +00:00
// 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
}
}