Skip to content

Commit

Permalink
feat: infinite scroll
Browse files Browse the repository at this point in the history
  • Loading branch information
Faizal Andyka committed May 21, 2022
1 parent a84da04 commit 2180515
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 11 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@logustra/vinscroll",
"version": "0.0.1",
"description": "An Infinite scroll component for vue 2-3",
"description": "A minimalist infinite scroll component for vue 2-3",
"keywords": [
"vue",
"vue3",
Expand Down
2 changes: 1 addition & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)
[![Commitizen](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli)

> An Infinite scroll component for vue 2-3
> A minimalist infinite scroll component for vue 2-3
## Cheer me on
If you like my works, you can cheer me on here 😆
Expand Down
51 changes: 47 additions & 4 deletions src/app.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,58 @@
<template>
<HelloWorld />
<div>
<Vinscroll
is-element
@load:more="onLoadMore"
>
<div style="height: 200px; border: 1px solid black; overflow: auto;">
<div
v-for="item in items"
:key="item"
style="padding: 5px; margin: 5px; background-color: green;"
>
{{ item }}
</div>
</div>
</Vinscroll>

<Vinscroll
@load:more="onLoadMore"
>
<div
v-for="item in items"
:key="item"
style="padding: 5px; margin: 5px; background-color: green;"
>
{{ item }}
</div>
</Vinscroll>
</div>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
import HelloWorld from './helloWorld.vue'
import {
defineComponent,
ref,
} from 'vue'
import Vinscroll from './vinscroll.vue'
export default defineComponent({
name: 'App',
components: {
HelloWorld,
Vinscroll,
},
setup() {
const items = ref([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
function onLoadMore() {
const length = items.value.length + 1
items.value.push(...Array.from({ length: 5 }, (_, index) => length + index))
}
return {
items,
onLoadMore,
}
},
})
</script>
5 changes: 0 additions & 5 deletions src/helloWorld.vue

This file was deleted.

130 changes: 130 additions & 0 deletions src/vinscroll.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
<script lang="ts">
import {
computed,
defineComponent,
h,
onMounted,
onUnmounted,
toRefs,
} from 'vue-demi'
export default defineComponent({
name: 'Vinscroll',
props: {
tag: {
type: String,
required: false,
default: 'div',
},
isElement: {
type: Boolean,
required: false,
default: false,
},
},
setup(props, { emit, slots }) {
const {
tag,
isElement,
} = toRefs(props)
/**
* DESC:
* event listener
*/
const LOAD_MORE = 'load:more'
const element = computed(() => {
let result = document.documentElement
/**
* DESC:
* use this element when the infinite scoll
* is in the element
*/
if (isElement.value)
result = (slots.default && slots.default()[0].el) as HTMLElement
return result
})
function onScroll() {
if (element.value && element.value.scrollTop > 0) {
/**
* DESC:
* calculations for how much the document
* has been scrolled from the top
*/
const scrollY = (
isElement.value
? element.value.scrollTop + element.value.clientHeight
: window.pageYOffset + window.innerHeight
)
/**
* DESC:
* calculation for mobile
*/
const downwardScrollY = Math.floor(scrollY)
/**
* DESC:
* calculation for desktop
*/
const upwardScrollY = Math.ceil(scrollY)
/**
* DESC:
* height of an element's content
* including content not visible on the screen due to overflow
*/
const scrollHeight = element.value.scrollHeight
/**
* DESC:
* set to true when the scroll has arrived at the bottom,
* both on desktop or mobile.
*/
const isArrivedBottom = downwardScrollY === scrollHeight || upwardScrollY === scrollHeight
/**
* DESC:
* fires immediately when the user scroll has arrived at the bottom
*/
if (isArrivedBottom) emit(LOAD_MORE)
}
}
onMounted(() => {
if (isElement.value)
element.value && element.value.addEventListener('scroll', onScroll)
else
window.addEventListener('scroll', onScroll)
})
onUnmounted(() => {
/**
* DESC:
* remove event listener to free up memory usage
*/
if (isElement.value)
element.value && element.value.removeEventListener('scroll', onScroll)
else
window.removeEventListener('scroll', onScroll)
})
/**
* DESC:
* passing html tag as string
* passing props as null
*/
return () => h(
tag.value,
null,
slots.default && slots.default(),
)
},
})
</script>

0 comments on commit 2180515

Please sign in to comment.