列表无限滚动(虚拟列表)

简介: 列表无限滚动(虚拟列表)

列表无限滚动需要考虑两点:

  1. 数据太多,要做虚拟列表
  2. 下拉到底,继续加载数据并拼接之前的数据


虚拟列表


只展示可视区域内的列表项目,动态计算可视区域内的列表项,删除非可视区域列表项。

(1)首先确定dom结构

  • 第一层作为容器层(infinite-list-container),目的是监听列表滚动,记录滚动位置scrollTop。
  • 第二层作为占位层(infinite-list-phantom),根据实际列表的长度占位,撑开空间,形成滚动条
  • 第三层作为列表层(infinite-list),列表数据展示的可视化区域,需要用transform:translate3D(x,y,z),这里的y指的是列表偏移量。

(2)监听数据

监听容器的scroll事件,获取滚动位置scrollTop

  • 可视区域高度:screenHeight
  • 列表每项高度:itemSize
  • 列表数据:listData
  • 当前滚动位置:scrollTop

(3)确定需要的数据

  • 滚动的位置:this.$ref.list.scrollTop

确定列表项的高度:itemSize = 100px

  • 可视区域的列表项的总数:visableCount = Math.ceil(screenHeight / itemSize)
  • 确定每次加载列表数据的条数: listData.length
  • 确定列表的实际的长度:listHeight = itemSize * listData.length
  • 开始索引:start = Math.floor(scrollTop / itemSize)
  • 结束索引:end = start + visableCount
  • 偏移量:scrollTop - (scrollTop % itemSize)

(4)代码

  <div class="infinite-list-container" ref="list" @scroll="scrollEvent">
        <div class="scrollTopBtn" @click="scrollToTop" v-show="end > 20"> 回到顶部</div>
        <div class="infinite-list-phantom" :style="{ height: listHeight + 'px' }"></div>
        <div class="infinite-list" :style="{ transform: getTransform }">
            <div class="infinite-list-item" v-for="item in visibleData" :key="item.id" @click="toDetail(item.id)" :style="{ height: itemSize + 'px',lineHeight: itemSize + 'px' }">
                <div class="left-section">
                    {{ item.title[0] }}
                </div>
                <div class="right-section">
                    <div class="title">{{ item.title }}</div>
                    <div class="desc">{{ item.content }}</div>
                </div>
            </div>
        </div>
    </div>
<script lang="ts">
import { Vue, Component } from "vue-property-decorator";
import Faker from "faker";
interface Data {
    title: string;
    content: string;
    id: number | string;
}
@Component
export default class VirtualList extends Vue {
    public readonly itemSize: number = 100;
    public listData: Data[] = [];
    // 可视区域高度
    public screenHeight: number =
        document.documentElement.clientHeight || document.body.clientHeight;
    // 可显示的列表项数
    public visibleCount: number = Math.ceil(this.screenHeight / this.itemSize);
    // 偏移量
    public startOffset: number = 0;
    // 起始索引
    public start: number = 0;
    // 结束索引
    public end: number = this.start + this.visibleCount;
    public $refs: {
        list: any;
    };
    // 列表总高度
    get listHeight() {
        return this.listData.length * this.itemSize;
    }
    // 偏移量对应的style
    get getTransform() {
        return `translate3d(0,${this.startOffset}px,0)`;
    }
    // 获取真实显示列表数据
    get visibleData() {
        return this.listData.slice(
            this.start,
            Math.min(this.end, this.listData.length)
        );
    }
    // 获取数据
    getTenListData() {
        if (this.listData.length >= 200) {
            return [];
        }
        return new Array(10).fill({}).map((item) => ({
            id: Faker.random.uuid(),
            title: Faker.name.title(),
            content: Faker.random.words(),
        }));
    }
    //初始化
    created() {
        this.listData = this.getTenListData();
    }
    //滚动顶部
    scrollToTop() {
        this.$refs.list.scrollTo({
            top: 0,
            left: 0,
            behavior: "smooth",
        });
    }
    //监听滚动事件
    public scrollEvent(e: any) {
        // 当前滚动位置
        const scrollTop = this.$refs.list.scrollTop;
        // 此时的开始索引
        this.start = Math.floor(scrollTop / this.itemSize);
        // 此时的结束索引
        this.end = this.start + this.visibleCount;
        //拼接数据
        if (this.end > this.listData.length) {
            this.listData = this.listData.concat(this.getTenListData());
        }
        // 此时的偏移量
        this.startOffset = scrollTop - (scrollTop % this.itemSize);
    }
}
</script>

(5)图示

目录
相关文章
|
1月前
|
移动开发 前端开发
VUE3一种用户可以设置显示隐藏列表内容的方法
VUE3一种用户可以设置显示隐藏列表内容的方法
22 0
|
1月前
|
JavaScript
【sgDrag】自定义组件:基于Vue开发支持批量声明拖拽元素、被碰撞元素,拖拽全过程监听元素碰撞检测并返回拖拽原始元素、克隆元素及其getBoundingClientRect对象和碰撞接触元素数组。
【sgDrag】自定义组件:基于Vue开发支持批量声明拖拽元素、被碰撞元素,拖拽全过程监听元素碰撞检测并返回拖拽原始元素、克隆元素及其getBoundingClientRect对象和碰撞接触元素数组。
|
6月前
|
JavaScript
虚拟列表
虚拟列表
84 0
|
9月前
|
JavaScript
vue项目:商品列表页的渲染,删除,搜索,面包屑导航
vue项目:商品列表页的渲染,删除,搜索,面包屑导航
90 0
jQuery实现下拉列表选择条目左右选择功能
jQuery实现下拉列表选择条目左右选择功能
|
JavaScript
Vue 根据鼠标悬停目标元素上方显示、隐藏指定元素交互实现
Vue 根据鼠标悬停目标元素上方显示、隐藏指定元素交互实现
363 0
|
容器
写了个自定义指令,支持elementUI2.0下拉框组件虚拟列表显示
由于业务对页面性能要求很高,如果下拉框数据很大,一个页面有多个下拉框,那么就导致页面很卡顿。由于elementPlus已经支持了下拉组件虚拟列表,但所在项目仍然使用elementUI2.0,所以需要自己扩展支持下拉组件虚拟列表
599 0
写了个自定义指令,支持elementUI2.0下拉框组件虚拟列表显示
|
前端开发 JavaScript 大数据
了解虚拟列表背后原理,轻松实现虚拟列表
在项目中,大数据渲染常常遇到,比如umy-ui(ux-table)虚拟列表table组件,vue-virtual-scroller以及react-virtualized 这些优秀的插件快速满足业务需要。
866 0
了解虚拟列表背后原理,轻松实现虚拟列表
|
前端开发
bootstrap 组件之 输入框组 超大屏幕 列表组件学习总结
bootstrap 组件之 输入框组 超大屏幕 列表组件学习总结