您是否有将其用于表格的示例? 我正在尝试使其正常运行,但我强烈怀疑它要么无效,要么我做错了什么。
我已经将outerTagName设置为“ table”,将innerTagName设置为“ tbody”,但是没有任何滚动。
这是我的代码,不确定是否有帮助(项目是对象列表):
<List
outerRef={this._list}
outerTagName="table"
innerTagName="tbody"
height={300}
itemData={items}
itemSize={() => 30}
itemCount={items.length}
itemKey={item => item.uniqueId}>
{({index, style, data}) => {
return (
<tr style={style} key={index}>
<td>Item {index}</td>
</tr>
);
}}
</List>
我认为这真的行不通。 据我所知, HTMLTableElement
并不真正以窗口组件所需的方式支持溢出。 您可以将样式更改为display: block
但是我仍然认为它不太可行。 (这是一个示例。)
你为什么需要桌子? 我认为您可以使用内联块或flex布局实现相同的列布局。
几件其他事情:
width
为List
key
到行中itemSize
只能是30
而不是() => 30
(它会稍微好一些)感谢您的快速回复。
我们已经讨论过将其重写为div,但是由于这是针对现有的相当大的组件,因此我们只想确保在开始重写之前先进行确认。 我还看到了有关rc-table的其他评论,因此认为它应该可以工作。
无论如何,不要介意重写,我认为应该值得。
我在行上没有键的情况下收到了关于键的React警告,考虑到我正在设置itemKey,这也让我感到困惑,所以不确定那里发生了什么。
谢谢
埃纳尔
2018年9月21日,16:52,Brian Vaughn [email protected]写道:
我认为这真的行不通。 据我所知,HTMLTableElement并不真正以窗口组件所需的方式支持溢出。 您可以将样式更改为display:block,但是我仍然认为效果不佳。
你为什么需要桌子? 我认为您可以使用内联块或flex布局实现相同的列布局。
几件其他事情:
您没有指定List的require参数宽度
您无需将键添加到行中
itemSize可以是30而不是()=> 30(它会稍微好一些)
-
您收到此消息是因为您创建了线程。
直接回复此电子邮件,在GitHub上查看,或使该线程静音。
我在行上没有键的情况下收到了关于键的React警告,考虑到我正在设置itemKey,这也让我感到困惑,所以不确定那里发生了什么。
这是不期望的。 您可以(通过代码沙箱)与我分享一个仿制案例吗?
哦,对不起。 我应该补充一点,如果您的itemKey
函数返回了某些项目的undefined
,则此情况仅会出现–在这种情况下,解决方法将是对该函数进行修复。
@bvaughn我没有发现有关溢出支持的任何特定限制因素。 奇怪的是,我想知道可能是什么。 我当然知道支持两者的核心功能可能是乏味的,但是它看起来仅是基础列表元素,这是当前实现者无法选择的。 对于我自己以及可能在固定标头方案中使用react-window的任何人来说,获得内置于表格布局中的表格支持将是很好的。 使用display:table确实需要“一些”开发开销,并且是可能会偶然使用表构建的周围应用程序的一次性布局。 我总是可以通过CSS调整溢出或其他属性(无论如何,我正在当前的实现中进行此操作)。 elementType道具是不可能的吗?
@bvaughn我没有发现有关溢出支持的任何特定限制因素。
也许我没有使用最好的措词-但是,如果您查看链接到的沙盒( rrn61wkzwm ),则会看到意外的行为。
这是HTML的另一个示例: lx65871p69
HTMLSelectElement
( <tbody>
)会忽略height
和overflow
类的样式,从而使其无法用于窗口显示。 您可以通过更改其显示模式( display: block
)“修复”此问题,但这违反了使用HTMLTableElement
的目的,因为它破坏了列的大小设置行为。
无论如何,对于窗口用例而言,该列的大小调整行为都从一开始就被破坏了,因为其大小取决于列中的内容(随着用户滚动,该内容将改变)。
但是它看起来似乎只是基本列表元素是当前实现者无法选择的所有元素...是否可以将elementType道具排除在外?
如果您确实想要( 2j0z718mwy ),您已经可以指定标签类型,尽管我看不到它能为您带来什么。
对于我自己以及可能在固定标头方案中使用react-window的任何人来说,获得内置于表格布局中的表格支持将是很好的。
由于上面我解释的原因,使用HTMLTableElement
是有问题的。 如果要使用具有固定标题的表格/网格布局,则可以使用常规列表组件之一来实现此目的: pk78pvwnkx
你为什么需要桌子? 我认为您可以使用内联块或flex布局实现相同的列布局。
也许需要某种可访问性的表结构(例如,与非语义div相比,屏幕阅读效果更好)? 我猜在这里。
在这种情况下,我将覆盖CSS显示样式以及表元素固有的任何其他样式。
大约九年前,我的经验是构建一个复杂的表组件(顶部和左侧的固定/固定标题,复杂的colspan / rowspan结构以及用于描述其背后结构的数据模型)(当时我们没有React,也没有可访问性问题,而且据我所知,没有虚拟化)是负责此组件的同事尝试在适当的表元素中实现它,努力迫使布局以某种方式运行,然后决定从纯JavaScript中实现表布局。绝对定位和大小的div。 该解决方案非常有效:不会出现奇怪的布局跳跃,平滑滚动(非逐行/逐列)等情况。
也许需要某种可访问性的表结构(例如,与非语义div相比,屏幕阅读效果更好)? 我猜在这里。
咏叹调角色可以用于此😄
超级周到,谢谢。 您只是救了我一个兔子洞,尝试了一个可以解决一个问题而又创建了另一个问题的原型。
你好
我试图找到一个现有线程,而不是创建一个新线程。 我希望我在一个好地方...
有没有一种方法可以让FixedSizeGrid
合并两个单元格(在我的上下文中可能更有意义)?
这个问题依赖于此处开始的另一个讨论,但是从更有意义的角度来看,我更喜欢在此处发布。
有没有一种方法可以为FixedSizeGrid合并两个单元格(在我的上下文中可能更有意义)?
否。不支持此功能。
@einarq @BlaineBradbury @sompylasar如果您仍然感兴趣,我设法使用表标签进行窗口工作。 实际上,我最终创建了一个包装react-window的库。 您可以在此处观看现场演示: https :
我想要表格标签
我很想标记并询问Brian,他对这种实现有何看法(因为他提到html表标记将不起作用)。 但是他已经对我足够了。 因此,我将其留给你们。
谢谢你。
@pupudu这是一个有趣的方法。 我不知道在标题和行中使用单独的<table>
标签是否会引起可访问性问题,但如果不是这样,那就太好了。
我正在尝试将react-datasheet
与react-window
,它基本上可以工作:
function sheetRenderer(props) {
const Row = ({ index, style }) => (
React.cloneElement(props.children[index], { style })
);
return (
<table className={props.className}>
<tbody>
<FixedSizeList
height={150}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</FixedSizeList>
</tbody>
</table>
)
}
export default function EntityTable(props: IEntityTableProps) {
const initialGrid = useMemo(() => {
return getTableGridFromCSV(props.entityListCSV);
}, [props.entityListCSV]);
const [modifiedGrid, updateModifiedGrid] = useImmer(initialGrid);
return (
<ReactDataSheet
data={modifiedGrid}
sheetRenderer={sheetRenderer}
valueRenderer={cell => cell.value}
onCellsChanged={changes => {
updateModifiedGrid(draft => {
changes.forEach(({ cell, row, col, value }) => {
draft[row][col].value = value || '';
});
});
}}
/>
);
}
function getTableGridFromCSV(csv: string) {
return csv.split('\n').map(row =>
row.split(',').map((cell, index) => {
if (index === 0) {
return {
value: cell,
forceComponent: true,
component: <button onClick={() => console.log(cell)}>{cell}</button>,
};
}
if (index === 2) {
return {
value: cell,
};
}
return {
value: cell,
component: <span>{cell}</span>,
};
}),
);
}
它呈现,唯一的问题是Warning: validateDOMNesting(...): <tr> cannot appear as a child of <div>.
index.js:1437 Warning: validateDOMNesting(...): <div> cannot appear as a child of <tbody>.
嘿,我正在用React-Table进行尝试,并注意到我必须使用div而不是表元素。 问题在于样式库(例如material / bootstrap)依赖于那些元素。 因此,将我的表模式更改为div而不是表元素需要做很多工作。 是否可以使用表元素进行差异比较,还是我现在必须创建自己的样式?
@simkessy除非您已经注意到,否则应该签出窗口表。 它允许使用html表格标签,从而允许我们重复使用现有样式。 必须承认,该表虽然不如react-table先进。
https://window-table.netlify.com/
@pupudu我对您的开源努力表示赞赏,并在决定尝试自行解决此问题之前,对代码进行了广泛的研究。 我只是想要其他人正在寻找的超级简单的东西:这个库但是带有表元素。
事实证明,我能够用很少的代码和很多创造力就可以做到这一点。 该代码非常简单,任何人都应该能够复制/粘贴并扩展到自己喜欢的地方。 @bvaughn在弄清楚
它的简称:
工作代码沙箱: https :
参考代码
import React from 'react'
import { useState, useRef, useContext } from 'react'
import { FixedSizeList, FixedSizeListProps } from 'react-window'
import { render } from 'react-dom'
/** Context for cross component communication */
const VirtualTableContext = React.createContext<{
top: number
setTop: (top: number) => void
header: React.ReactNode
footer: React.ReactNode
}>({
top: 0,
setTop: (value: number) => {},
header: <></>,
footer: <></>,
})
/** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/
function VirtualTable({
row,
header,
footer,
...rest
}: {
header?: React.ReactNode
footer?: React.ReactNode
row: FixedSizeListProps['children']
} & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) {
const listRef = useRef<FixedSizeList | null>()
const [top, setTop] = useState(0)
return (
<VirtualTableContext.Provider value={{ top, setTop, header, footer }}>
<FixedSizeList
{...rest}
innerElementType={Inner}
onItemsRendered={props => {
const style =
listRef.current &&
// @ts-ignore private method access
listRef.current._getItemStyle(props.overscanStartIndex)
setTop((style && style.top) || 0)
// Call the original callback
rest.onItemsRendered && rest.onItemsRendered(props)
}}
ref={el => (listRef.current = el)}
>
{row}
</FixedSizeList>
</VirtualTableContext.Provider>
)
}
/** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/
function Row({ index }: { index: number }) {
return (
<tr>
{/** Make sure your table rows are the same height as what you passed into the list... */}
<td style={{ height: '36px' }}>Row {index}</td>
<td>Col 2</td>
<td>Col 3</td>
<td>Col 4</td>
</tr>
)
}
/**
* The Inner component of the virtual list. This is the "Magic".
* Capture what would have been the top elements position and apply it to the table.
* Other than that, render an optional header and footer.
**/
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
function Inner({ children, ...rest }, ref) {
const { header, footer, top } = useContext(VirtualTableContext)
return (
<div {...rest} ref={ref}>
<table style={{ top, position: 'absolute', width: '100%' }}>
{header}
<tbody>{children}</tbody>
{footer}
</table>
</div>
)
}
)
/**
* Render Our Example
**/
render(
<VirtualTable
height={300}
width="100%"
itemCount={1000}
itemSize={36}
header={
<thead>
<tr>
<th>Index</th>
<th>Header 2</th>
<th>Header 3</th>
<th>Header 4</th>
</tr>
</thead>
}
row={Row}
footer={
<tfoot>
<tr>
<td>Footer 1</td>
<td>Footer 2</td>
<td>Footer 3</td>
<td>Footer 4</td>
</tr>
</tfoot>
}
/>,
document.querySelector('main')
)
@jamesmfriedman喜欢这个方法。 使用Context实现这一目标的确很有趣。 我喜欢这样的事实,即您只渲染一张表格,而在我的方法中,我渲染两个表格,一个用于标题,一个用于主体。 这在窗口表用户中引起了很多混乱(没有看到即将到来的tbh)。
如果您不介意,我会尝试在窗口表中使用这些想法。 我认为最大的挑战是弄清楚如何根据内容自动调整行的大小(至少这是windo-table的最大挑战)。
@jamesmfriedman看起来非常有前途。 @bvaughn您对此方法有任何担忧吗?
@jamesmfriedman似乎标题与内容一起向上滚动。 是否可以使其具有粘性?
实际上这是可能的,而不是特定于此实现的。 只需使用HTML表格元素在粘性标头周围进行一些搜索即可。 我隐约记得,这样做的方法实际上是使TH元素的位置保持粘性。
@jamesmfriedman非常感谢您的示例👍它很有帮助@marink这是粘性标头的示例https://codesandbox.io/s/react-window-with-table-elements-jj70e您需要添加style={{ position: 'sticky', top: 0 }}>
到th
标签
@jamesmfriedman非常感谢这个例子。 我将研究使用它。 但是我认为使用top:0和粘性位置而不是重新计算top并在table元素上具有绝对位置将是正确的方法。 因为如果您使用位置粘性在th元素上获取粘性标题,那么所有内容都会在快速滚动时被搞砸。
所以第79行是<table style={{ top: 0, position: 'sticky', width: '100%' }}>
这也解决了滚动问题,即当您在底部时继续滚动时。
使用HTML表的另一个很好的理由是支持IE11。 我正在使用FixedSizeList
,然后使用CSS网格对其进行样式设置。 但是,当您需要添加其他功能(如响应式列,具有不同大小的列等)并使其与IE11一起使用时,最终会产生大量的代码。 HTML表格默认情况下不使用任何代码。
IE11不再是您应该支持的东西了:)
每个FE开发人员都希望IE11死亡。 但是不幸的是,由于我们甚至无法想象的原因,一些公司/人员仍然坚持使用它。 希望这只是未来几年的时间。 在此之前,无论我们是否喜欢,我们都将需要支持IE11。
对我来说,这也是一剂难以下咽的药。
@ olafur164感谢您对固定标头在快速滚动时不会中断的修复。 您是否知道是否有一种方法可以保持“粘性”外观,因为它现在一次平滑地滚动一次,而不是平滑地滚动?
让我分享我对react-virtualized (甚至是react-window问题页面)和一些材料UI库(称为material-table)的经验,其中出现相同的问题(结合了虚拟化的表格元素): https : validateDOMNesting(...)
警告之类的问题。
@jamesmfriedman非常感谢您的示例👍很有帮助@marink这是粘性标头的示例。 您需要在
th
标记中添加style={{ position: 'sticky', top: 0 }}>
嘿@JCofman ,我尝试了您的CSS修复程序,但对我来说不起作用。 这是代码沙箱示例-https://codesandbox.io/s/react-window-with-table-elements-forked-huti6 ? file
有两个问题-
提前致谢 :)
@jamesmfriedman喜欢这个方法。 使用Context实现这一目标的确很有趣。 我喜欢这样的事实,即您只渲染一张表格,而在我的方法中,我渲染两个表格,一个用于标题,一个用于主体。 这在窗口表用户中引起了很多混乱(没有看到即将到来的tbh)。
如果您不介意,我会尝试在窗口表中使用这些想法。 我认为最大的挑战是弄清楚如何根据内容自动调整行的大小(至少这是windo-table的最大挑战)。
我最终找到了一个非常类似的解决方案,因为我将display: grid
和display: contents
用作行,因此基本上遵守了table > tr
元素的约束。
您使用context + refs调用内部方法,但是,这完全没有必要,因为可以通过查找第一个孩子的style.top值来实现相同的目的:
const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>(
function Inner({ children, ...rest }, ref) {
const { header, footer } = useContext(VirtualTableContext)
const {style} = children[0].props;
return (
<div {...rest} ref={ref}>
<table style={style}>
{header}
<tbody>{children}</tbody>
{footer}
</table>
</div>
)
}
)
库在为每一行执行createElement时都会提供样式道具,并且由于您特定的Row
组件不会将style
分配给tr
,因此您不会要么把它们传下来。
最近,我想知道这样的事情。 如果我们要通过css自定义属性使用伪元素(在after之前)使用填充来移动整个表主体怎么办🤔
在使用react-virtual的示例中为https://codesandbox.io/s/poc-react-virtual-table-jyz0m
我绝对需要一个表,以便可以实现所需的UX,并且对使其与react-window
一起使用的解决方法不满意。
我最后只是将虚拟化逻辑自己提取到一个钩子中,并用两个表实现了它,一个表用于标题,第二个表用于内容,类似于上面发布的内容。 我的方法的不同之处在于,第二个表的标题仍然保留在标记中,但在视觉上隐藏起来,因此仍可访问,而第一个表的标题仅用于有视力的用户,并且位置固定。该代码大大简化了。
只是把它扔在那里,以防有人想要尝试。
@pupudu我对您的开源努力表示赞赏,并在决定尝试自行解决此问题之前,对代码进行了广泛的研究。 我只是想要其他人正在寻找的超级简单的东西:这个库但是带有表元素。
事实证明,我能够用很少的代码和很多创造力就可以做到这一点。 该代码非常简单,任何人都应该能够复制/粘贴并扩展到自己喜欢的地方。 @bvaughn在弄清楚
_它的简称_:
- 渲染后捕获第一行的“顶部”样式
- 将该值存储在React.Context中,以便我们可以传递它
- 将值应用于将移动的表组件,而不是行本身
- 为诸如页眉和页脚之类的内容添加其他插槽。
- 库的人机工程学原理不允许事物整齐地传递,因此React.Context是克服跨组件通信的英雄。
工作代码沙箱: https :
参考代码
import React from 'react' import { useState, useRef, useContext } from 'react' import { FixedSizeList, FixedSizeListProps } from 'react-window' import { render } from 'react-dom' /** Context for cross component communication */ const VirtualTableContext = React.createContext<{ top: number setTop: (top: number) => void header: React.ReactNode footer: React.ReactNode }>({ top: 0, setTop: (value: number) => {}, header: <></>, footer: <></>, }) /** The virtual table. It basically accepts all of the same params as the original FixedSizeList.*/ function VirtualTable({ row, header, footer, ...rest }: { header?: React.ReactNode footer?: React.ReactNode row: FixedSizeListProps['children'] } & Omit<FixedSizeListProps, 'children' | 'innerElementType'>) { const listRef = useRef<FixedSizeList | null>() const [top, setTop] = useState(0) return ( <VirtualTableContext.Provider value={{ top, setTop, header, footer }}> <FixedSizeList {...rest} innerElementType={Inner} onItemsRendered={props => { const style = listRef.current && // @ts-ignore private method access listRef.current._getItemStyle(props.overscanStartIndex) setTop((style && style.top) || 0) // Call the original callback rest.onItemsRendered && rest.onItemsRendered(props) }} ref={el => (listRef.current = el)} > {row} </FixedSizeList> </VirtualTableContext.Provider> ) } /** The Row component. This should be a table row, and noted that we don't use the style that regular `react-window` examples pass in.*/ function Row({ index }: { index: number }) { return ( <tr> {/** Make sure your table rows are the same height as what you passed into the list... */} <td style={{ height: '36px' }}>Row {index}</td> <td>Col 2</td> <td>Col 3</td> <td>Col 4</td> </tr> ) } /** * The Inner component of the virtual list. This is the "Magic". * Capture what would have been the top elements position and apply it to the table. * Other than that, render an optional header and footer. **/ const Inner = React.forwardRef<HTMLDivElement, React.HTMLProps<HTMLDivElement>>( function Inner({ children, ...rest }, ref) { const { header, footer, top } = useContext(VirtualTableContext) return ( <div {...rest} ref={ref}> <table style={{ top, position: 'absolute', width: '100%' }}> {header} <tbody>{children}</tbody> {footer} </table> </div> ) } ) /** * Render Our Example **/ render( <VirtualTable height={300} width="100%" itemCount={1000} itemSize={36} header={ <thead> <tr> <th>Index</th> <th>Header 2</th> <th>Header 3</th> <th>Header 4</th> </tr> </thead> } row={Row} footer={ <tfoot> <tr> <td>Footer 1</td> <td>Footer 2</td> <td>Footer 3</td> <td>Footer 4</td> </tr> </tfoot> } />, document.querySelector('main') )
谢谢你的支持,有没有人尝试过(成功地)将它与InfiniteLoader
组件一起使用?假设是因为无限加载程序正在将意外的道具传递给innerElementType。
最有用的评论
@pupudu我对您的开源努力表示赞赏,并在决定尝试自行解决此问题之前,对代码进行了广泛的研究。 我只是想要其他人正在寻找的超级简单的东西:这个库但是带有表元素。
事实证明,我能够用很少的代码和很多创造力就可以做到这一点。 该代码非常简单,任何人都应该能够复制/粘贴并扩展到自己喜欢的地方。 @bvaughn在弄清楚
它的简称:
工作代码沙箱: https :
参考代码