Skip to content

Instantly share code, notes, and snippets.

@ckvv
Created May 31, 2023 11:06
Show Gist options
  • Save ckvv/e4d0e41f0410c01a430fdef9b133f121 to your computer and use it in GitHub Desktop.
Save ckvv/e4d0e41f0410c01a430fdef9b133f121 to your computer and use it in GitHub Desktop.
Vue虚拟列表实现
<script setup lang="ts">
import { computed, ref, unref } from 'vue';
const props = defineProps<{
items: any[]
itemSize: number
buffer: number
}>();
const wrapRef = ref();
const startIndex = ref(0);
const pool = computed(() => {
return props.items.slice(unref(startIndex), unref(startIndex) + props.buffer)
});
const computedTotalHeight = computed(() => {
return props.items.length * props.itemSize
});
const computedTop = computed(() => {
return unref(startIndex) * props.itemSize
});
function handleScroll(e: any) {
const wrapper = wrapRef.value;
if(wrapper){
startIndex.value = wrapper.scrollTop / props.itemSize
}
}
</script>
<template>
<div ref="wrapRef" @scroll="handleScroll">
<div :style="{ height: `${computedTotalHeight}px` }">
<div :style="{ transform: `translateY(${computedTop}px)` }">
<template v-for="item in pool">
<slot :item="item"></slot>
</template>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { computed, ref, unref } from 'vue';
const props = defineProps<{
items: any[]
itemSize: number
buffer: number
}>();
const wrapRef = ref<HTMLElement>();
const startIndex = ref(0);
const pool = computed(() => {
return props.items.slice(unref(startIndex), unref(startIndex) + props.buffer)
});
function handleScroll(e: any) {
const wrapper = wrapRef.value;
if(wrapper){
startIndex.value = wrapper.scrollTop / props.itemSize
}
}
const computedPaddingTop = computed(() => {
return unref(startIndex) * props.itemSize
});
const computedPaddingBottom = computed(() => {
return(props.items.length - unref(props.buffer) - unref(startIndex)) * props.itemSize
});
</script>
<template>
<div ref="wrapRef" @scroll="handleScroll">
<div :style="{ paddingTop: `${computedPaddingTop}px`, paddingBottom: `${computedPaddingBottom}px` }">
<template v-for="item in pool">
<slot :item="item"></slot>
</template>
</div>
</div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment