vue3 overflow 长列表虚拟滚动的知识记录

其实我是要在手机端实现虚拟列表(web端其实有很实用的插件可以用,没必要自己实现)。找了两天资料,也没有找到一个我满意的方案。最后看到一片比较通俗易懂的文章,按照他的方案实现了基本的虚拟列表。

PS:功能虽然实现了,但是还有小问题,比如快速滚动时效果一般。性能也还未测试。

uniapp下的坑

做虚拟列表,首先得能拿到滚动条的数据,也就是滚动监听事件。网上找了好久,基本就两个方案:

  1. 基于document什么的监听“scroll”事件。这个试了,确实可以哈。但是,如果我一个页面分两边,分别有两个滚动区域呢?这能监听到吗?存疑,我没有测试了
  2. 用vue提供(真的是vue提供的吗?官方文档翻遍都找到说明)的@scroll,来监听滚动事件。

当然,我选的第二个方案。于是,我就被折磨了很久。我的代码大概是这样写的:

    <view ref="scrollRef" style="overflow: auto" @scroll="scroll">
        <view v-for="item in 100" :key="item">
            <text>标题{{ item }}text>
        view>
    view>

滚动确实没问题哈,滚动事件也是成功调用了,但是,里面没有网上查到的那些属性呀,什么scrollTopscrollHeight的,都找不到,明明他们也这么写的,为什么他们的有:
vue3 overflow 长列表虚拟滚动的知识记录_第1张图片
翻遍vue官网,uniapp官网,都找不到相关的说明。于是,我就怀疑是我用的,他们用的


,就只有这个的区别了。于是就尝试一下,果然,有了。

uniapp官网说用代替

。也没说有这方面的区别呀。属实很坑。

PS:我现在用的H5,这样用没问题,但是编译成app和小程序不知道还行不行。

相关用法

首先,用@scroll监听了滚动事件后:滚动会触发:

    function scroll(event: any) {
        console.log(event);
        console.log(event.target.scrollTop); // 理解为滚动的距离,单位应该是px
   	}

其次呢,我上面还用了ref="scrollRef"绑定dom,这样就可以获得实例:

    const scrollRef = ref(null);
    function scroll(event: any) {
        console.log(event.target.scrollTop);
        console.log(scrollRef.value.scrollTop);
    }

上面两个属性能得到一样的数值。

scrollRef还能用来控制滚动轴的位置:

        scrollRef.value.scrollTop = 0; // 直接设置滚动条的位置
        
        // 也可使用scrollTo方法设置,支持设置滚动的动画。但是我没测试出效果
        scrollRef.value.scrollTo({
            top: 0,
            left: 0,
            behavior: "smooth",
        });

这个也是很实用的功能,没他很多功能就无法实现了。上面两种方法都可以。
可以看看这篇的介绍:https://blog.csdn.net/small_white_123/article/details/117792575

至于整体的虚拟滚动方案,等我实测没问题了,再写文章记录。

切换页面再切回来,导致滚动条自动回到起点的问题

这个问题在虚拟列表中尤为明显,因为会留空白。

vue3 overflow 长列表虚拟滚动的知识记录_第2张图片
我是先滚动了一段距离,然后点了购物车,再回到商品,看吧,两个滚动条都回到原点了。左侧因为没有使用虚拟滚动,还算正常点,只是回到起点而已,右侧直接留空。
因为这种自动重置滚动条不会触发滚动事件,我们的那些滚动参数还保持着原样,上面都是padding留空的,所以看过去就是一片空白。

我百度查了一圈,这个问题,在几年前就有人在讲了,可是到现在还是存在,难道这几年的技术进步仍然没有从根本上解决这问题吗?我有点不能理解,找不到答案。

当然,这个问题很多人会遇到,所以肯定有解决方案:

解决方案

首先,uniapp在切换页面时,会调用onHideonShow,这两个的作用如名,好理解,所以我理所当然的认为,在隐藏界面时,调用onHide记录当前滚动条的位置,然后回到页面时调用onShow重新设置滚动条位置即可解决。

然后实测并不是这么回事,onShow里面设置滚动条是不生效的。我是很不理解原因的。然后网上给的方案是,用定时器,在onShow结束后再设置滚动条,这样就可以了:

    // 下面是为了解决页面切换后滚动条回到起点的问题
    let scrollLeftTop = 0; // 记录左侧分类栏滚动条位置
    let scrollRightTop = 0; // 记录右侧商品栏滚动条位置
    // 在切换页面时会调用
    onHide(() => {
        scrollLeftTop = leftScroll.value.scrollTop;
        scrollRightTop = rightScroll.value.scrollTop;
    });
    // 再次页面显示时,会调用
    onShow(() => {
        // 还不能直接在这个onShow中对滚动条赋值,会不生效,得用定时器延迟一点执行才行
        var timer = setTimeout(() => {
            leftScroll.value.scrollTop = scrollLeftTop;
            rightScroll.value.scrollTop = scrollRightTop;
            clearTimeout(timer);
        }, 10);
    });

但是这种方案其实是有弊端的,是会触发页面重塑还是回流啥的。会对页面的性能造成影响,但目前也只找到这种方案是简单有效的。很无奈,以后要是有好方案再回来记录。

PS:我不知道在web端,会不会存在这个问题。移动端是这样的。

你可能感兴趣的:(前端,vue3,overflow,长列表,scroll,虚拟滚动)