我有一个使用
@tanstack/react-table
的表格,并使用 ShadCN Table Component 进行样式设置,并对粘性功能和 ShadCN Tooltip Component 进行了一些调整
我将
Thead
(th
) 中的所有 TableHeader
(thead
) 组件粘在顶部。因此,当用户垂直滚动表格时,Thead
(th
) 会粘在顶部。
我将第一列
TableCell
的 (td
) 粘在左侧。因此,当用户水平滚动表格时,该列的数据会粘在左侧。
问题是,为了使这项工作有效,我需要在各个元素上添加
z-index
,因此工具提示要么卡在 Thead
或其他 TableCell
后面。所以,不太确定如何同时拥有粘性的Thead
和TableCell
以及Tooltips
的
如果您想尝试一下,这里有一个 StackBlitz 环境 可以重现问题?
const Header: React.FC<{ title: string }> = ({ title }) => (
<div className="font-bold min-w-[300px] bg-slate-300 h-16 flex justify-center items-center">
{title}
</div>
);
//////
{
accessorFn: (row) => `${row.firstName} ${row.lastName}`,
id: 'fullName',
header: () => <Header title="Name" />,
cell: (info) => {
return (
<div className="font-bold min-w-[300px]">
<TooltipProvider>
<Tooltip defaultOpen={info.row.index === 0}>
<TooltipTrigger asChild>
<span>{info.getValue()}</span>
</TooltipTrigger>
<TooltipContent className="max-w-[200px] w-full min-w-[150px]">
<p>This</p>
<p>Is</p>
<p>A</p>
<p>Tooltip</p>
<p>Test</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
);
},
footer: (props) => props.column.id,
meta: {
sticky: true,
stickyLeft: true,
},
},
import { cn } from '@/lib/utils';
import { type ColumnMeta } from '@tanstack/react-table';
import * as React from 'react';
export interface TableProps extends React.HTMLAttributes<HTMLTableElement> {
tableClassName?: string;
}
const Table = React.forwardRef<HTMLTableElement, TableProps>(({ className, tableClassName, ...props }, ref) => (
<div className={cn('w-full overflow-x-auto data-table-container border rounded-md', className)}>
<table ref={ref} className={cn('w-full caption-bottom text-sm relative data-table', tableClassName)} {...props} />
</div>
));
Table.displayName = 'Table';
const TableHeader = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<thead ref={ref} className={cn(className)} {...props} />
));
TableHeader.displayName = 'TableHeader';
const TableBody = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<tbody ref={ref} className={cn(className)} {...props} />
));
TableBody.displayName = 'TableBody';
const TableFooter = React.forwardRef<HTMLTableSectionElement, React.HTMLAttributes<HTMLTableSectionElement>>(({ className, ...props }, ref) => (
<tfoot ref={ref} className={cn('bg-primary font-medium text-primary-foreground', className)} {...props} />
));
TableFooter.displayName = 'TableFooter';
export interface TableRowProps extends React.HTMLAttributes<HTMLTableRowElement> {
isLoading?: boolean;
noHover?: boolean;
}
const TableRow = React.forwardRef<HTMLTableRowElement, TableRowProps>(({ className, isLoading, noHover, ...props }, ref) => (
<tr
ref={ref}
className={cn('transition-colors', !isLoading && '[&>*]:data-[state=selected]:bg-muted', !noHover && !isLoading && '[&>*]:hover:bg-muted', className)}
{...props}
/>
));
TableRow.displayName = 'TableRow';
export interface TableHeadProps<TData, TValue> extends React.ThHTMLAttributes<HTMLTableCellElement>, ColumnMeta<TData, TValue> {
isLoading?: boolean;
last?: boolean;
}
const TableHead = React.forwardRef<HTMLTableCellElement, TableHeadProps<any, any>>(
({ className, sticky, stickyLeft, stickyRight, isLoading, last, ...props }, ref) => {
return (
<th
ref={ref}
className={cn(
'h-10 px-4 text-left align-middle font-medium text-muted-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] relative',
sticky && 'sticky -top-[1px] z-[7] bg-background',
stickyLeft && 'sticky -left-[1px] z-[9] bg-background',
stickyRight && 'sticky -right-[1px] z-[9] bg-background',
stickyRight && last && 'z-[8]',
isLoading && 'min-w-[100px]',
className,
)}
{...props}
/>
);
},
);
TableHead.displayName = 'TableHead';
export interface TableCellProps<TData, TValue> extends React.TdHTMLAttributes<HTMLTableCellElement>, ColumnMeta<TData, TValue> {}
const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps<any, any>>(({ className, sticky, stickyLeft, stickyRight, ...props }, ref) => (
<td
ref={ref}
className={cn(
'table-cell px-4 py-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px] relative',
sticky && 'sticky -right-[1px] z-[5] bg-background',
stickyLeft && 'sticky -left-[1px] z-[6] bg-background',
stickyRight && 'sticky -right-[1px] z-[5] bg-background',
className,
)}
{...props}
/>
));
TableCell.displayName = 'TableCell';
const TableCaption = React.forwardRef<HTMLTableCaptionElement, React.HTMLAttributes<HTMLTableCaptionElement>>(({ className, ...props }, ref) => (
<caption ref={ref} className={cn('mt-4 text-sm text-muted-foreground', className)} {...props} />
));
TableCaption.displayName = 'TableCaption';
export { Table, TableHeader, TableBody, TableFooter, TableHead, TableRow, TableCell, TableCaption };
任何帮助将不胜感激!
您可以考虑在悬停时增加单元格的
z-index
,因为这可能是工具提示显示时:
<TableCell
…
hasTooltip={cell.getContext().column.columnDef.id === 'fullName'}
>
const TableCell = React.forwardRef<HTMLTableCellElement, TableCellProps<any, any>>(({ …, hasTooltip, … }, ref) => (
<td
ref={ref}
className={cn(
…
hasTooltip && 'hover:z-10',
…
)}
{...props}
/>
));
尽管您仍然会遇到一些卡顿行为,例如当悬停的单元格部分位于应位于顶部的不同单元格后面时:
否则,您可以考虑使用 Portals 在表格外渲染工具提示元素,这样在 z 堆栈中组织元素会更容易,尽管我不确定 Shadcn/Radix Tooltip 组件与这种方法。