如何在 antd Table 的选择框中添加 Tooltip?
mrlmx opened this issue · comments
Tips,如果你着急想要解决方案:
- antd 版本 ≥ 4.1.0: 点这里(官方解决方案)
- Hack 解决方案,做试验的版本为 antd@4.20.0 ,不一定适用其他版本,思考仅供参考
下面是实现这个功能的心路历程,个人觉得比较有意思,所以记录下来 😜。
前段时间,产品提了一个需求:想要给那些 Table
里面禁止选中的行中加上 Tooltip
,提示为什么不允许选中,提升用户体验,就像下面这样 👇🏻:
我们知道 antd 的 Table 组件可以通过 rowSelection
属性,控制表格行是否可选择,所以我就直接去 rowSelection 这部分文档里面找相关的配置,可是上下 简单浏览 一番,发现并没有这方面的内容。
所以又直奔 issue,搜索关键字:rowSelection tooltip ,找到了下面几个相关的问题:
- how to add some tip message on table checkbox by rowSelection
- Table 的 rowSelection 希望透出 checkbox 或者 radio 的显示配置
- How to add tooltip in rowSelection table
找到的唯一可行性方案是:自定义 Column。
It's not a common requirement. You can customize the column by your own: https://codesandbox.io/s/1q2x7jx9nj
看这架势,意思是需要咱们自己手动实现一套完整的选择逻辑啊。这让时间本不宽裕的我们,更是雪上加霜 😫。
所以,我随即得出了结论:
这个需求暂时做不了。🤥
可是,这确实是个有意义需求啊 ~ 😭,既然是正经需求,要不,咱们再想想办法 🤔 ?
Hack 思路
因为偶尔会看 antd
的代码,所以本地保存的有他的代码,打开代码的第一步就是 pull 一下最新代码,antd 每周发一版,是在太厉害了(小声BB 🤫)
PS:以下代码的版本均为:antd@4.20.0
再次经过一番 简单浏览 之后,找到了 渲染 CheckBox 的代码:
// Record checked
return {
node: (
<Checkbox
{...checkboxProps}
indeterminate={mergedIndeterminate}
checked={checked}
skipGroup
onClick={(e) => e.stopPropagation()}
onChange={({ nativeEvent }) => {
// 省略此部分源码内容
}}
/>
),
checked,
};
可以看到:{...checkboxProps}
这里是通过解构,直接把 checkboxProps
传给了 CheckBox 组件。
那是不是说,我可以在 checkboxProps
中添加任何 CheckBox 组件支持的属性呢 😏?
然后我在 getCheckboxProps
中返回了如下信息:
<Table
rowSelection={{
getCheckboxProps: (record) => {
return {
disabled: true,
children: <span style={{ color: "red" }}>Test</span>,
};
},
}}
columns={columns}
dataSource={data}
/>;
嘿嘿嘿,他出现了 😜。
验证猜想之后,把代码进行如下改造:
- 新增一个
span
,设置为 CheckBox 的高宽 - 在
span
外面包上 Tooltip 组件 - 通过
absolutely
将span
绝对定位到 CheckBox 的位置 - 设置
z-index
,将span
放在 CheckBox 上方
<Table
rowSelection={{
getCheckboxProps: (record) => {
const props = {};
if (record.age < 18) {
props.disabled = true;
props.children = (
<Tooltip title="小于 18 岁">
<span
style={{
width: 16,
height: 16,
position: "absolute",
top: 19,
left: 8,
zIndex: 1,
border: "1px solid red",
}}
/>
</Tooltip>
);
}
return props;
},
}}
columns={columns}
dataSource={data}
/>;
但是还有些瑕疵:展示 Tooltip 的 CheckBox 纵向错位了,通过审查元素发现,是因为我们加了 children
,把 CheckBox 给挤到旁边了。
既然被挤走了,那把容器宽度缩小一点 🤔,有一个简单的方法是直接通过 css 覆盖修改这一列的宽度。
- rowSelection 有一个控制选择框宽度的属性:
columnWidth
,但就算设置的很小,整列还是会被内容撑开 - 下面的代码仅用来做演示,没有没有加前缀,注意不要把全局的 Table 列宽都修改了。
.ant-table-selection-column > .ant-checkbox-wrapper{
width: 16px;
}
.ant-table-selection-column > .ant-radio-wrapper{
width: 16px;
}
好了,到了这一步,Table 的 CheckBox 上添加 Tooltip 已经完成了,Radio 思路也一致,只需要把 span
的坐标调整一下,然后加上圆角即可,完整代码可以见本文开头的链接。
发现原生支持
需求顺利上线之后,想着写篇文章记录一下解决方案,贴到上面几个 issue 中,这样可以在官方支持之前,让大家先临时实现这个功能。
所以想顺带看一下 antd Table 中选择列的渲染逻辑,避免有其他被我忽略的细节导致 Bug。没想到这一看,就把我看懵了,我发现了 renderSelectionCell 这个函数 😱。
const renderSelectionCell = (_: any, record: RecordType, index: number) => {
const { node, checked } = renderCell(_, record, index);
if (customizeRenderCell) {
return customizeRenderCell(checked, record, index, node);
}
return node;
};
竟然有个调用 customizeRenderCell
函数的逻辑,一看这函数名,我就觉得有点不对劲🤔,而且还把相关的参数都传了进去。
通过一番顺藤摸瓜,发现了根源。
首先是从 rowSelection
中获取 renderCell
参数,并且重命名为 customizeRenderCell。
export default function useSelection<RecordType>(
rowSelection: TableRowSelection<RecordType> | undefined,
config: UseSelectionConfig<RecordType>
): [TransformColumns<RecordType>, Set<Key>] {
const {
// 省略此部分源码内容
...,
renderCell: customizeRenderCell,
// 省略此部分源码内容
...
} = rowSelection || {};
}
然后在 Table 中找到了调用 useSelection
的代码片段。
const [transformSelectionColumns, selectedKeySet] = useSelection<RecordType>(rowSelection, {
prefixCls,
data: mergedData,
pageData,
getRowKey,
getRecordByKey,
expandType,
childrenColumnName,
locale: tableLocale,
getPopupContainer,
}
);
而 useSelection
的第一个参数 rowSelection
,就是我们在 Table 中传入的 rowSelection 属性 😨。
所以,文档中的 rowSelection
的这个 renderCell
属性竟然被我完整忽略了 😰。。。
好了,既然发现了这个秘密,那咱们就试一下效果吧 🙄。
<Table
rowSelection={{
renderCell(checked, record, index, node) {
if (record.age < 18) {
return <Tooltip title="未满 18 岁">{node}</Tooltip>;
}
return node;
},
getCheckboxProps: (record) => {
let checkboxProps = {};
if (record.age < 18) {
checkboxProps.disabled = true;
}
return checkboxProps;
},
}}
columns={columns}
dataSource={data}
/>;
不得不说,简直完美 🤗。
修改官方文档
鉴于在写这个需求之前,也问过其他同事,有没有做过在 Table 的可选列中展示 Tooltip 的需求,他们给我的答复都是官方文档中没有相关配置,暂时不支持这个功能,就把这类需求都拒绝了。
所以我感觉应该有很大一部分小伙伴会忽略掉 rowSelection
的这个 renderCell
属性,既然如此,就在官方文档中把这个场景提一下,可以让其他小伙伴少走些弯路,早点下班 😜。
写好相关示例并完善文档之后,就给官方提了一个 PR,又是美好的一天 😄。