网页端是有多少 DOM 元素就渲染多少元素,不管这些元素是不是用户当前视口可见的,所以元素一多就会很卡。每次都要专门把渲染的逻辑写成虚拟滚动来解决这个问题,但用过的一些虚拟滚动库总是有各种各样的限制或小毛病,例如要求元素等高,滚动到底部不对劲等等。

我就很好奇其他端,像移动端和桌面端都是怎么解决这个问题的?搜索 [安卓 虚拟滚动] 还搜不到什么东西
最新回复 (21)
  • sduoduo2334月前
    引用2
    安卓是 recyclerview
  • abcbuzhiming4月前
    引用3
    移动端我不清楚。但是桌面端的话,我没听说过传统 UI 的列表控件有用虚拟滚动的,实际上,当元素量够大的时候,一样会卡的,只是桌面端大部分时候处于性能溢出的状态,且内存管够,所以一般遇不到那个能让你卡的数量级。
  • Irisxx4月前
    引用4
    主要是归功于对象池的重用机制,辅之以 LRU 这些缓存机制优化。
  • verrickt4月前
    引用5
    微软的 GUI 框架把相关的技术叫做 UI Virtualization ,有兴趣可以看看
  • lmw26164月前
    引用6
    android 用 recyclerview ,也是类似于虚拟滚动
  • chiaf4月前
    引用7
    你搜索 iOS UITableView 应该能搜到????
    很早之前的经典面试题,说一下 UITableView Cell 的复用原理
  • kemchenj4月前
    引用8
    其它端不清楚,iOS 端其实就是虚拟滚动,列表会维护一个重用池,把不可见的 cell 塞进去,然后需要展示的时候从里面拿 cell 出来显示,如果发现不够就再补充新的进来

    iOS 封装得还行,但也免不了各种限制和小毛病,都是需要开发者额外做一些处理去完善体验,例如预先计算每个元素的高度以便把列表撑开之类的...

    感兴趣的话可以搜一下“UITableView 重用”
  • xiebaiyuan4月前
    引用9
    回收,重用,缓存
  • UnluckyNinja4月前
    引用10
    如果从只渲染可见部分的组件来看,那基本上都可以算作虚拟滚动(否则就是加硬件了)
    你用的库总是有各种各样的不完美,可能是因为复杂度难以实现/怕导致库臃肿(所以固定高度),或者虚拟高度计算不正确。
    根本原因在于虚拟高度需要根据内部组件的实际大小调整以正确计算滚动位置。
    你看像 twitter 也是虚拟滚动,但你要是快速拉到中间再缓慢向上拉,会发现 twitter 的滚动条也在闪,(猜测)这就是在修正假定的未渲染元素的高度到渲染完后实际高度,并相应调整总高度。
    如果你是想写前端的一个虚拟滚动组件,可以参考 VueUse 推荐的这个独立虚拟滚动组件 https://vue-virtual-scroller-demo.netlify.app/dynamic
  • superkeke4月前
    引用11
    iOS UITableView ,android recyclerview ,移动端这是最基本的了。
  • tangmanger4月前
    引用12
    wpf 大列表有虚拟化 只渲染展示的
  • shunia4月前
    引用13
    解决方案全都是虚拟列表,没有例外。方案细节基本就是元素复用、列表两端留缓冲区、高度重新计算等。

    你觉得不好用是因为这个没有完美的解决方案,比如你说的等高问题,应该是想要考虑保留列表滚动位置,否则根本不必等高。

    这些都是一说出来就明白的基础原理,并不是哪个技术方案本身能解决的,桌面端列表大了不虚拟也会卡的爆炸,只是在同一个硬件设施上比网页端能多承受一些而已。
  • hefengwqz4月前
    引用14
    @abcbuzhiming 桌面端我们之前开发性能调优工具的时候,数据表格就是做的虚拟滚动,Android 手机录制几十秒解析出来的数据就有百万条。
  • duanxianze4月前
    引用15
    都是虚拟滚动,上千上万的元素啥玩意也顶不住的,只不过浏览器的限制导致 dom 复用总有问题,安卓 ios 和 win 内置的相关逻辑
  • chniccs4月前
    引用16
    安卓最开始的时候是 listview ,后面换成了 recyclerview ,不过都是复用,但是当年试过,不复用的话,列表内容不复杂,不是太快的滑动也没有很卡,只是内存会爆
  • wya934月前
    引用17
    虚拟分页,
  • iOCZS4月前
    引用18
    反正你只能看到一个屏幕的东西,我提前准备好三屏,够你看的了
  • zpxshl4月前
    引用19
    你搜不到是因为,安卓列表基本都用 rv 实现,不存在问题,自然没有“解决方案”
  • unco0205114月前
    引用20
    移动端的列表控件会在背后做非常多的工作,以便解决列表渲染的性能.就拿 android 端的 recyclerview 举例:
    1. 视图复用( View Recycling ):RecyclerView 通过 ViewHolder 模式来复用已经创建的视图。简单来说,当某个视图滚出屏幕时,它不会被销毁,而是会被放入一个"回收池"中。当新的视图需要显示时,RecyclerView 会从这个回收池中取出一个视图,并绑定新的数据。这大大减少了视图创建和销毁的开销。

    2 .按需加载( Lazy Loading ):RecyclerView 只会创建和绑定当前屏幕上可见的视图,以及少量即将进入屏幕的视图。这样可以有效减少内存消耗和处理时间。

    3. 布局管理器( LayoutManager ):RecyclerView 使用 LayoutManager 来决定如何在屏幕上排列子视图。不同的 LayoutManager 可以实现不同的布局方式,如线性布局、网格布局等。LayoutManager 负责计算哪些视图需要显示,哪些可以复用。

    4 .差分更新( Diff Util ):RecyclerView 支持高效的数据更新。当数据集发生变化时,可以使用 DiffUtil 来计算新旧数据集之间的差异,只更新那些真正改变的部分,而不是重新渲染整个列表。
  • debuggerx4月前
    引用21
    条目非等高的长列表还要带滚动条,原理上就没办法高效、完美解决,只能是各种取舍,有时是技术上,有时是设计上。
    或者换句话说,只要原理上无法避免大量元素 layout 的场景,怎么都会卡,只是在同等硬件配置下不同的语言和框架会出现卡顿现象的量级会有所不同。
  • codehz4月前
    引用22
    (其实浏览器也不会绘制超过屏幕的内容( edge 有几个版本你就会在滚动过快的时候看到白屏被一个个方块填上的过程),但超过屏幕的内容不止是绘制的问题,还有布局等其他因素需要计算,加上为了 js 访问方便而设计的对象接口的 overhead 才会显得不能装太多东西,实际上就单纯说显示一个巨大的表格来说浏览器问题不是很大,好多设计起来就只有单页的文档(例如隔壁的 rust 的某文档,html5 的单页 spec ),其内容长度远超一般“无限滚动”正常用户能滚动到的范围,也可以顺利的在浏览器上呈现。。。(当然和一般无限滚动场景不同的是,它内容上是较为简单的,计算布局的压力也会小很多)
    桌面端除了用虚拟滚动的思路之外,还有一种叫 imgui 的思路,其抛弃了控件的抽象,根据滚动位置直接计算出需要展示的范围,然后每次都只画用到的部分,也可以解决这个问题==(有一些商业表格控件就是这个思路)
    之所以虚拟滚动一类的机制需要使用“复用”,其本质不是绘制元素有多慢,而是为了表达这个 UI 对象抽象带来的额外成本很高,不能简单的丢弃再重建,或者干脆建立一大堆放着
  • 回复请 登录 or 快速注册
返回