问题::我希望有一个React Virtualized table,它可以占用最大的高度(例如500px
)。在表格的最后 visible 行的下面,我想添加另一个元素。像这样:
If the content of the table is shorter than 500px
+-----------------------------------------+ ----+
| Header1 | Header2 | ... | |
+---------+---------+---------------------+ | less than 500px,
| row1 | row1 | row1 | | say 200px
+---------+---------+---------------------+ |
| row2 | row2 | row2 | |
+---------+---------+---------------------+ ----+
Other content
If the content of the table is longer than 500px
+-----------------------------------------+^ ----+
| Header1 | Header2 | ... || |
+---------+---------+---------------------+| | 500px,
| row1 | row1 | row1 || | notice the
+---------+---------+---------------------+| | scroll bar
| row2 | row2 | row2 || |
+---------+---------+---------------------+| |
| row3 | row3 | row3 || |
+---------+---------+---------------------+| |
| row4 | row4 | row4 |V ----+
Other content
换句话说:表格与“其他内容”之间不应有白色间隙,而且表格最多应占用500px。
问题:我该如何实现?
我的尝试:我尝试过使用AutoSizer,但问题是:
如果AutoSizer
包含在高度固定的div
中(例如:height: 500px
),则表格和“其他内容”(如果表格太短;所以我得到的是这样:
+-----------------------------------------+ ----+
| Header1 | Header2 | ... | |
+---------+---------+---------------------+ | less than 500px,
| row1 | row1 | row1 | | say 200px
+---------+---------+---------------------+ |
| row2 | row2 | row2 | |
+---------+---------+---------------------+ ----+
|
| gap of
| 300px
|
|
Other content ----+
如果AutoSizer
包含在高度最大的div
中(例如:max-height: 500px
),则仅显示标题,而“其他内容”将在标题上方(即,包含的div
不会随着表的增长而增长,因此AutoSizer
不会执行任何操作);我得到的是这样的:
Other content ----------------------------+
| Header1 | Header2 | ... |
+---------+---------+---------------------+
(如果我同时给出最大高度和固定高度,那么当然,固定高度会“获胜”,结果与第一种情况相同)。
备注:我一点也不确信AutoSizer
是这里的正确方法,因此我愿意接受任何其他建议(如果可能的话,无需进一步的第三方)依赖关系,但是如果没有其他方法也可以)。
供参考的来源:
<div>
<div style={{height: "100px", maxHeight: "500px"}}>
<AutoSizer>
{({height, width}) => (
<Table
ref="Table"
disableHeader={false}
headerClassName=""
headerHeight={40}
height={height}
rowClassName=""
rowHeight={40}
rowGetter={rowGetter}
rowCount={6}
width={width}>
<Column
label="Index"
cellDataGetter={({rowData}) => rowData.index}
dataKey="index"
width={60}
/>
<Column
label="Text1"
cellDataGetter={({rowData}) => rowData.text1}
dataKey="text1"
width={90}
/>
<Column
label="Text2"
cellDataGetter={({rowData}) => rowData.text2}
dataKey="text2"
width={90}
/>
</Table>
)}
</AutoSizer>
</div>
<div>Some other text</div>
</div>
约束说明:该解决方案必须与Virtualized-React表一起使用。不能选择使用HTML表。 (上面我只是说,AutoSizer
可能不是正确的解决方案,但我确实需要用到表。)
answer中的建议方法:我尝试将@jered的建议应用于我的案例,然后再次得到一个扩展到最大最大高度的表格。我不确定我做错了什么,还是建议的方法在这种情况下根本不起作用
<div style={{ display: 'flex',
border: '1px solid red',
flexDirection: 'column' }}>
<div style={{
display: 'flex',
maxHeight: '500px',
border: '1px solid blue',
padding: '2px',
margin: '2px',
overflow: 'scroll'
}}>
<Table
ref="Table"
disableHeader={false}
headerClassName=""
headerHeight={40}
height={900}
rowClassName=""
rowHeight={40}
rowGetter={rowGetter}
rowCount={6}
width={400}>
<Column
label="Index"
cellDataGetter={({rowData}) => rowData.index}
dataKey="index"
width={60}
/>
<Column
label="Text1"
cellDataGetter={({rowData}) => rowData.text1}
dataKey="text1"
width={90}
/>
<Column
label="Text2"
cellDataGetter={({rowData}) => rowData.text2}
dataKey="text2"
width={90}
/>
</Table>
</div>
<div style={{ display: 'flex',
flexDirection: 'column',
border: '1px solid green',
padding: '2px',
margin: '2px' }}>Some other text</div>
</div>
相关问题:基本上,React Virtualized表创建了一个div
大小为0px x 0px
且内容可见的dispatch_queue_t queue;
@synchronized (self) {
queue = _mySerialQueue;
}
dispatch_async(queue, ^{ // Crash happens here
if (_ivar) {
...
}
});
。因此,如果可以考虑溢出的大小,则可以解决该问题。这本身就是一个有趣的问题,因此,我将继续进行后续工作,但请保留此问题,因为针对此特定情况可能会有更好的解决方案。
又一次更新:我注意到,如果我将表格放在flex容器中,则不会创建零尺寸的div。
答案 0 :(得分:0)
无需诉诸React或任何复杂的方法。只需在简单的CSS中使用FlexBox。
给出“表”和“其他内容” display: flex
的容器,并在包装max-height
的内部元素上设置<table>
。 FlexBox子项将尝试扩展以填充其内容所需的空间而不再容纳更多空间,但不会扩展到其max-height
(如果已设置)。
注意:将代码段展开到全屏即可查看完整效果。
function adjustrows() {
let val = document.getElementById("slider").value;
let table = document.getElementById("table");
let inner = `
<tr>
<th>foo</th>
<th>bar</th>
<th>baz</th>
<th>foo</th>
<th>bar</th>
<th>baz</th>
</tr>
`;
for (let i = 0; i < val; i++) {
inner += `
<tr>
<td>foo</td>
<td>bar</td>
<td>baz</td>
<td>foo</td>
<td>bar</td>
<td>baz</td>
</tr>
`;
}
table.innerHTML = inner;
document.getElementById("numrows").innerText = val;
}
adjustrows();
table, tr, th, td {
box-sizing: border-box;
border: 1px solid gray;
}
table {
flex-grow: 1;
}
th {
background: lightgray;
}
label {
display: flex;
justify-content: center;
margin: 5px;
}
#numrows {
margin: 0 10px;
}
#flex-container {
display: flex;
border: 1px solid red;
flex-direction: column;
}
#table-container {
display: flex;
max-height: 500px;
border: 1px solid blue;
padding: 2px;
margin: 2px;
overflow: scroll;
}
#other-content-container {
display: flex;
flex-direction: column;
border: 1px solid green;
padding: 2px;
margin: 2px;
}
.placeholder {
background: darkgray;
margin: 10px;
height: 120px;
}
<div id="flex-container">
<label>
<strong>Number of table rows:<span id="numrows"></span> </strong>
<input id="slider" onchange="adjustrows();" oninput="adjustrows();" type="range" min="0" max="100" value="1" />
</label>
<div id="table-container">
<table id="table">
</table>
</div>
<div id="other-content-container">
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
<div class="placeholder"></div>
</div>
</div>
请注意,如果您从表中删除某些<tr>
元素,使其比500px
短,那么#table-container
只会缩小以适应。
一如既往,Mozilla开发人员网络在FlexBox上有some pretty good info。
答案 1 :(得分:0)
我能够使用 rowRenderer 和 refs 为 React 虚拟化List 完成此操作,但我相信它也适用于 Table。
const [listHeight, setListHeight] = useState(500);
<List height={listHeight} .../>
const rowRefs = useRef(dataInList.map(() => React.createRef<HTMLDivElement>()));
const rowRenderer = useCallback(
({ key, index, style, parent }: ListRowProps) => {
const item = dataInList[index];
return (
<CellMeasurer
key={key}
cache={cache.current}
columnIndex={0}
parent={parent}
rowIndex={index}>
<div ref={rowRefs.current[index]}>
Your row info goes here
</div>
</CellMeasurer>
);
},
[formatted]
);
offsetHeight
对行的高度求和,并将状态 listHeight 设置为该高度或您想要的任何最大高度(以两者中的较小者为准)。useEffect(() => {
const domListHeight = rowRefs.current
.filter((e: any) => e.current)
.reduce((acc: any, e: any) => acc + e.current.offsetHeight, 0);
const MAX_HEIGHT = 500;
const usableHeight = domListHeight < MAX_HEIGHT ? domListHeight : MAX_HEIGHT;
setListHeight(usableHeight);
}, [dataInList]);
总结:组件将在最大高度渲染列表,然后计算所有行组合的实际高度,如果总高度小于预期的最大高度,组件将从头开始重新渲染列表新的低高度。