资讯详情

资讯详情

让虚拟滚动列表自动撑满容器:react-virtualized AutoSizer 从监听链路到 Flex 适配

让虚拟滚动列表自动撑满容器react-virtualized AutoSizer 从监听链路到 Flex 适配【免费下载链接】react-virtualizedReact components for efficiently rendering large lists and tabular data项目地址: https://gitcode.com/gh_mirrors/re/react-virtualized拉宽浏览器窗口后列表右侧留出一大片空白把侧边栏收起来列表又突然挤成窄条。虚拟滚动组件 List、Table、Grid 都要求你给出明确的 width / height 像素值可响应式列表的这两个值恰恰取决于父容器。AutoSizer 就是 react-virtualized 里专门补上这个缺口的组件它挂在父容器上量出可用的宽高再通过 children 函数交给子组件。一句话机制给容器装上量尺把 AutoSizer 理解成给父容器装了一把量尺它渲染一个占位 div负责测量父节点可用尺寸你通过 children 函数拿到 width / height再决定画什么。最小可运行的版本长这样import { AutoSizer } from react-virtualized; export function AutoSizerDemo() { return ( div style{{ height: 100vh, display: flex }} AutoSizer {({ width, height }) ( div style{{ width, height, background: #eef }} {width} x {height} /div )} /AutoSizer /div ); }窗口怎么拉占位 div 就跟着变占满父容器。量尺是 AutoSizer 的全部工作虚拟滚动的组件只负责拿到尺寸后正常渲染。尺寸到底从哪来这里先纠正一个常见误解AutoSizer 用的不是 ResizeObserver而是仓库内 vendored 的 detect-element-resize 算法source/vendor/detectElementResize.js。它会在挂载时往父节点里注入一个隐藏的测量 div把父节点position: static改成relative然后监听测量 div 的 scroll 事件——容器一变形内部 trigger 就滚动scroll 事件随之触发。精简后的链路是这样的// 挂载时 addResizeListener(parentNode, onResize); // 注入测量 div 挂 scroll 监听 onResize(); // 首次主动量一次 // 每次触发 onResize () { const width parentNode.offsetWidth - paddingLeft - paddingRight; const height parentNode.offsetHeight - paddingTop - paddingBottom; if (sizeChanged(width, height)) setState({ width, height }); };数据流就是一条直线容器变形 → 测量 div 产生 scroll → 回调里读offsetWidth / offsetHeight并减去父级 padding →setState→ React 重渲染 →children({ width, height })拿到新值。顺带说父级 padding 会被自动扣除所以带内边距的容器不用你自己算。与 List / Table 的三档组合 第一档一行式透传行高固定时最常用rowHeight传普通数字AutoSizer {({ width, height }) ( List width{width} height{height} rowCount{1200} rowHeight{40} rowRenderer{({ index, key, style }) ( div key{key} style{style} task-{index} /div )} / )} /AutoSizer第二档行高不固定但希望有测量缓存用 CellMeasurer 包一层。差异只在两处deferredMeasurementCache换成缓存实例、rowHeight换成缓存的取值函数AutoSizer 那部分一行不动const cache new CellMeasurerCache({ fixedWidth: true, minHeight: 40 }); AutoSizer {({ width, height }) ( List width{width} height{height} rowCount{500} deferredMeasurementCache{cache} rowHeight{cache.rowHeight} rowRenderer{({ index, key, parent, style }) ( CellMeasurer cache{cache} parent{parent} columnIndex{0} rowIndex{index} {({ measure, registerChild }) ( div ref{registerChild} style{style} onDoubleClick{measure} {node-${index}} /div )} /CellMeasurer )} / )} /AutoSizer动态高度在 Grid / Table 上同理new CellMeasurerCache({ fixedHeight: false })配合 Grid 的rowHeight{cache.rowHeight}即可。第三档是表格AutoSizer 照常包在最外层Table 吃尺寸Column 管列AutoSizer {({ width, height }) ( Table width{width} height{height} headerHeight{32} rowHeight{40} rowCount{data.length} rowGetter{({ index }) data[index]} Column labelnode dataKeyid width{120} / Column labelload dataKeyload width{120} / Column labelregion dataKeyregion width{160} / /Table )} /AutoSizer配置项速查children是唯一必传项签名({ width, height }) ReactNodeAutoSizer 的全部产出就藏在这个参数里子组件想拿多少尺寸自己挑。defaultHeight/defaultWidth决定首次渲染的尺寸默认都是 0——做 SSR 时用它们给首帧一个合理兜底挂载后立刻被真实测量值覆盖。disableHeight/disableWidth各自关掉一个维度的自动管理判断依据是这个维度要不要跟容器走列表高度写死 480 但宽度要跟着拉就disableHeight后自己写height{480}children 里只透传 width。onResize在每次尺寸变化后触发参数同样是{ width, height }适合埋点、通知外部状态同步不传时是空函数无副作用。布局适配的坑Flex、Grid 与初始为 0 Flex 里 AutoSizer 撑爆。症状是列表把兄弟元素挤没、滚动区高度变成 0或页面越拉越长。根因在源码里写得很直白AutoSizer 的根 div 默认被设成width: 0; height: 0见source/AutoSizer/AutoSizer.js中 render 的 outerStyle而 flex 容器不会因为一个 0 尺寸的子项约束布局内容又贪心地要占满可用空间两者叠加就形成增长循环。修法是中间垫一个块级元素让 flex 先给它定好尺寸AutoSizer 再去填满这个块div style{{ display: flex }} aside style{{ width: 220 }}sidebar/aside div style{{ flex: 1 1 auto, minWidth: 0 }} AutoSizer{renderList}/AutoSizer /div /divGrid 中缺min-width: 0的坑更隐蔽。症状是宽表格或宽列表撑开网格轨道出现横向溢出。根因是 grid item 默认min-width: auto不会被内容压缩到 min-content 以下轨道被撑宽AutoSizer 测到的也是被挤压后的宽度滚动区域直接被裁掉。修法是在放 AutoSizer 的网格子项上显式放行收缩.grid .list-cell { min-width: 0; overflow: auto; }还有一类经典问题AutoSizer 一直报 0。它只会填满父级不会反过来撑开父级所以父级或更上层没有确定高度时量出来的就是 0。最简单的诊断是给父级加个背景色看看真实尺寸确认是高度缺失就补height: 100%或flex: 1做 SSR 的话再用defaultHeight兜住首帧。高频 resize 下的性能处理拖窗口时 resize 是连续触发的AutoSizer 每次变化都会setStateReact 18 的自动批处理能挡住大部分但你在onResize里如果还有自己的逻辑上报、同步布局就需要自己降频我一般会包一层节流const notifyResize throttle(({ width, height }) { window.__layoutEventBus?.emit(list:resize, { width, height }); }, 100); AutoSizer onResize{notifyResize}{renderList}/AutoSizer另外提一句React 18 的useSyncExternalStore给了尺寸订阅一个潜在替代方案——自己写个基于 ResizeObserver 的subscribe / getSnapshot封装成 hook就能绕开 AutoSizer 的测量机制获得对测量时机的完全控制。对现有 react-virtualized 项目来说这属于优化项不必急着替换。延伸资源docs/AutoSizer.mdAutoSizer 完整属性表与官方 List 示例查参数语义看它docs/usingAutoSizer.mdFAQFlex 嵌套、高度为 0、与 InfiniteLoader 组合的问法基本都有source/AutoSizer/AutoSizer.example.js与source/CellMeasurer/CellMeasurer.DynamicHeightList.example.js想看虚拟滚动列表接 AutoSizer 的完整跑法按这两个文件抄就行。【免费下载链接】react-virtualizedReact components for efficiently rendering large lists and tabular data项目地址: https://gitcode.com/gh_mirrors/re/react-virtualized创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →