Test.vue 1.67 KB
<template>
    <div class="container" ref="container" :style="{ height: containerHeight }">
        <div class="empty" :style="{ height: emptyHeight }"></div>
        <ul class="list" :style="{ transform: `translateY(${translateY})` }">
            <li v-for="item in listData" :key="item" class="item" :style="{ height: itemHeight }">{{ item }}</li>
        </ul>
    </div>
</template>

<script>
import {computed, onMounted, ref} from 'vue'

export default {
    setup() {
        const oriData = Array.from({length: 100}, (v, k) => k)
        const itemHeight = 20
        const emptyHeight = itemHeight * oriData.length
        const containerHeight = window.innerHeight
        const itemCount = Math.ceil(containerHeight / itemHeight)
        const container = ref(null)
        const start = ref(0)
        const translateY = ref(0)
        const listData = computed(() => {
            return oriData.slice(start.value, start.value + itemCount + 1)
        })
        onMounted(
            () => {
                container.value.addEventListener(
                    'scroll',
                    e => {
                        const {scrollTop} = e.target
                        start.value = Math.floor(scrollTop / itemHeight)
                        translateY.value = scrollTop + 'px'
                    }
                )
            }
        )
        return {
            listData,
            container,
            translateY,
            containerHeight: containerHeight + 'px',
            itemHeight: itemHeight + 'px',
            emptyHeight: emptyHeight + 'px'
        }
    }
}
</script>
<style lang="less" scoped>
.container {
    overflow: auto;
    display: flex;
}
</style>