当没有数据(过滤后)时,React表标头宽度正在发生变化
我正在研究一个具有分类和过滤功能的反应表。当我过滤且没有返回数据(空表)时,标题的宽度没有保持固定,它们会相应地减少到标题标题的长度。发生这种情况是因为当没有数据时,tbody是完全空的,因此没有标头可以用于定义其宽度的单元。
您可以在渲染每个单元格时在架构中看到,我将其分配为课程。我在样式表中使用该类别为单元格提供了特定的宽度。我希望所有单元格的固定宽度为140px,只有摘要单元格(任务类型)的固定宽度为360px。这对单元格非常有用,当有数据时,标题会遵循细胞宽度。
查看图片(由于隐私 +我只显示一行,我必须介绍数据) - 实际上,它还有更多。您可以在图片中看到标题宽度与单元格的宽度匹配。
现在,一旦我过滤数据,并且过滤器输入与任何数据都不匹配,则标题会降低到取决于标题标题长度的宽度。请参阅图片:
最好的比较是彼此顶部的两个标头的图片:
我尝试了很多事情:从使用useblock/absolute/absolute/flexlayOut钩到分配模式中的宽度而不是通过CSS类,可以与CSS一起玩并尝试不同的选项,但到目前为止,没有任何作用。
我将感谢任何提示和建议。
这是表UI的代码:
const TaskManagerTable = (props) => {
const {columns, data} = props;
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data,
},
useFilters,
useSortBy,
);
return (
<>
<table className={CLASS_NAMES.TABLE}{...getTableProps()}>
<thead className={CLASS_NAMES.TABLE_HEAD}>
{headerGroups.map(headerGroup => {
const {key, ...restHeaderGroupProps} = headerGroup.getHeaderGroupProps()
return (
<tr className={CLASS_NAMES.HEADER_ROW} key={key} {...restHeaderGroupProps}>
{headerGroup.headers.map(column => {
const {key, ...restColumn} = column.getHeaderProps();
return (
<th className={CLASS_NAMES.HEADER_CELL} key={key} {...restColumn}
style={{
cursor: column.canSort ? 'pointer' : 'auto',
}}
>
{column.render('Header')}
<span className={CLASS_NAMES.SORT} {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.isSorted ?
<div className={CLASS_NAMES.ICON_SORTED}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div>
: column.canSort
? <div className={CLASS_NAMES.ICON_CAN_SORT}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div> : ''
}
</span>
<span className={CLASS_NAMES.FILTER}>
{column.canFilter ? column.render('Filter') : null}
</span>
</th>
)
})}
</tr>
)
})}
</thead>
<tbody {...getTableBodyProps}>
{rows.map(row => {
prepareRow(row)
const {key, ...restRowProps} = row.getRowProps();
return (
<tr key={key} {...restRowProps}>
{row.cells.map(cell => {
const {key, ...restCellProps} = cell.getCellProps();
return (
<td key={key} {...restCellProps}>
{cell.render('Cell')}
</td>
);
})}
</tr>
)
})}
</tbody>
</table>
</>
)
};
TaskManagerTable.propTypes = {
columns: PropTypes.array,
data: PropTypes.array,
};
const mapDispatchToProps = {};
export default connect(null, mapDispatchToProps)(TaskManagerTable);
这是架构:
export default [
{
Header: 'ID',
accessor: 'key',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const key = _.get(row, 'original.key');
return (
<div className={CLASS_NAMES.ID_CELL}>
<a href={`some link goes here`} target="_blank" rel="noopener noreferrer">{key}</a>
</div>
)
}
},
{
Header: 'Category',
accessor: 'category',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const category = _.get(row, 'original.category');
return (
<div className={CLASS_NAMES.CATEGORY_CELL}>
{category}
</div>
)
}
},
{
Header: 'Subcategory',
accessor: 'subCategory',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const subCategory = _.get(row, 'original.subCategory');
return (
<div className={CLASS_NAMES.SUBCATEGORY_CELL}>
{subCategory}
</div>
)
}
},
{
Header: 'Task Title',
accessor: 'summary',
className: 'summary',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const summary = _.get(row, 'original.summary');
return (
<div className={CLASS_NAMES.SUMMARY_CELL}>
{summary}
</div>
)
}
},
{
Header: 'Priority',
accessor: 'priority',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const priority = _.get(row, 'original.priority');
return (
<div className={CLASS_NAMES.PRIORITY_CELL}>
{priority}
</div>
)
}
},
{
Header: 'Status',
accessor: 'status',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const status = _.get(row, 'original.status');
return (
<div className={CLASS_NAMES.STATUS_CELL}>
{status}
</div>
)
}
},
{
Header: 'Task Type',
accessor: 'type',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
}
]
最后是SCSS:
table {
width: 100%;
thead {
position: sticky;
top: 0;
background-color: white;
tr {
text-align: left;
text-transform: uppercase;
color: #91a4c3;
font-weight: 400;
font-size: 12px;
th {
padding-left: 10px;
padding-bottom: 10px;
.sort-container {
margin-left: 25px;
position: absolute;
}
.filter-container {
margin-left: 30px;
position: absolute;
}
.icon-can-sort, .filter-component-hide {
display: none;
}
.filter-component-show {
display: block;
}
&:hover {
.icon-can-sort, .filter-component-hide {
display: block;
}
}
@include relative();
:nth-child(4) {
min-width: 360px;
}
}
}
}
tbody {
overflow-y: auto;
@include scrollBar();
tr {
box-shadow: 0px 1px 5px 0 rgba(104, 105, 111, 0.09);
height: 45px;
color: #6a7097;
text-transform: capitalize;
td {
padding-left: 10px;
}
.id-cell,
.category-cell,
.subcategory-cell,
.priority-cell,
.status-cell,
.type-cell,
{
min-width: 140px;
}
.summary-cell {
min-width: 360px;
}
}
}
}
I am working on a react-table that has sort and filter functionalities. When I filter and there is no data to be returned (empty table), the headers' widths are not staying fixed, they get reduced accordingly to the length of the header title. This is happening because when there is no data, tbody is completely empty, thus there are no cells that the headers can use for defining their widths.
You can see that in the schema when I am rendering each cell, I am assigning it a class. I use that class in the stylesheet to give the cells a specific width. I want all the cells to have a fixed width of 140px, and only the summary cell (task type) to have a fixed width of 360px. This works great for the cells, and when there is data the headers follow the cell widths.
See the picture (I had to cover the data due to privacy + I am showing only one row) - in reality, it has more. You can see in the picture that the header widths are matching the cells' widths.
Now, as soon as I filter the data out, and the filter input does not match any of the data, the headers get reduced to a width that depends on the length of the header titles. See picture:
The best comparison would be the following pictures of both headers placed on top of each other:
I tried many things: from using the useBlock/Absolute/FlexLayout Hooks to assigning the widths in the schema instead of via a CSS class, to playing around with CSS and trying out different options, but so far nothing works.
I would be thankful for any tips and suggestions.
Here is the code for the table UI:
const TaskManagerTable = (props) => {
const {columns, data} = props;
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data,
},
useFilters,
useSortBy,
);
return (
<>
<table className={CLASS_NAMES.TABLE}{...getTableProps()}>
<thead className={CLASS_NAMES.TABLE_HEAD}>
{headerGroups.map(headerGroup => {
const {key, ...restHeaderGroupProps} = headerGroup.getHeaderGroupProps()
return (
<tr className={CLASS_NAMES.HEADER_ROW} key={key} {...restHeaderGroupProps}>
{headerGroup.headers.map(column => {
const {key, ...restColumn} = column.getHeaderProps();
return (
<th className={CLASS_NAMES.HEADER_CELL} key={key} {...restColumn}
style={{
cursor: column.canSort ? 'pointer' : 'auto',
}}
>
{column.render('Header')}
<span className={CLASS_NAMES.SORT} {...column.getHeaderProps(column.getSortByToggleProps())}>
{column.isSorted ?
<div className={CLASS_NAMES.ICON_SORTED}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div>
: column.canSort
? <div className={CLASS_NAMES.ICON_CAN_SORT}>
<SortIcon dir={column.isSortedDesc ? 'desc' : 'asc'} onClick={_.noop} />
</div> : ''
}
</span>
<span className={CLASS_NAMES.FILTER}>
{column.canFilter ? column.render('Filter') : null}
</span>
</th>
)
})}
</tr>
)
})}
</thead>
<tbody {...getTableBodyProps}>
{rows.map(row => {
prepareRow(row)
const {key, ...restRowProps} = row.getRowProps();
return (
<tr key={key} {...restRowProps}>
{row.cells.map(cell => {
const {key, ...restCellProps} = cell.getCellProps();
return (
<td key={key} {...restCellProps}>
{cell.render('Cell')}
</td>
);
})}
</tr>
)
})}
</tbody>
</table>
</>
)
};
TaskManagerTable.propTypes = {
columns: PropTypes.array,
data: PropTypes.array,
};
const mapDispatchToProps = {};
export default connect(null, mapDispatchToProps)(TaskManagerTable);
Here is the schema:
export default [
{
Header: 'ID',
accessor: 'key',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const key = _.get(row, 'original.key');
return (
<div className={CLASS_NAMES.ID_CELL}>
<a href={`some link goes here`} target="_blank" rel="noopener noreferrer">{key}</a>
</div>
)
}
},
{
Header: 'Category',
accessor: 'category',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const category = _.get(row, 'original.category');
return (
<div className={CLASS_NAMES.CATEGORY_CELL}>
{category}
</div>
)
}
},
{
Header: 'Subcategory',
accessor: 'subCategory',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const subCategory = _.get(row, 'original.subCategory');
return (
<div className={CLASS_NAMES.SUBCATEGORY_CELL}>
{subCategory}
</div>
)
}
},
{
Header: 'Task Title',
accessor: 'summary',
className: 'summary',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const summary = _.get(row, 'original.summary');
return (
<div className={CLASS_NAMES.SUMMARY_CELL}>
{summary}
</div>
)
}
},
{
Header: 'Priority',
accessor: 'priority',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const priority = _.get(row, 'original.priority');
return (
<div className={CLASS_NAMES.PRIORITY_CELL}>
{priority}
</div>
)
}
},
{
Header: 'Status',
accessor: 'status',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
},
Cell: ({row}) => {
const status = _.get(row, 'original.status');
return (
<div className={CLASS_NAMES.STATUS_CELL}>
{status}
</div>
)
}
},
{
Header: 'Task Type',
accessor: 'type',
Filter: ({ column }) => {
return (
<ReactTableFilter containerClassName={CLASS_NAMES.TASK_MANAGER_FILTER_CONTAINER}
column={column}
popoverInner={<FreeTextFilter handleChangeFilter={column.setFilter} filter={column.filterValue}/>}
/>
)
}
]
And finally here is the SCSS:
table {
width: 100%;
thead {
position: sticky;
top: 0;
background-color: white;
tr {
text-align: left;
text-transform: uppercase;
color: #91a4c3;
font-weight: 400;
font-size: 12px;
th {
padding-left: 10px;
padding-bottom: 10px;
.sort-container {
margin-left: 25px;
position: absolute;
}
.filter-container {
margin-left: 30px;
position: absolute;
}
.icon-can-sort, .filter-component-hide {
display: none;
}
.filter-component-show {
display: block;
}
&:hover {
.icon-can-sort, .filter-component-hide {
display: block;
}
}
@include relative();
:nth-child(4) {
min-width: 360px;
}
}
}
}
tbody {
overflow-y: auto;
@include scrollBar();
tr {
box-shadow: 0px 1px 5px 0 rgba(104, 105, 111, 0.09);
height: 45px;
color: #6a7097;
text-transform: capitalize;
td {
padding-left: 10px;
}
.id-cell,
.category-cell,
.subcategory-cell,
.priority-cell,
.status-cell,
.type-cell,
{
min-width: 140px;
}
.summary-cell {
min-width: 360px;
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论