- 作者:老汪软件技巧
- 发表时间:2024-09-13 00:04
- 浏览量:
前言
老板:xxx, 你能不能把表格里面的数据弄一个复制的,我每次都要选中去cv很麻烦的。
我:让我想想。
略做思考
我用的是Antd组件库,在表格每一列render的时候通过一个通用自定义组件CopyText去复制,以便在任何可以复制的地方都可以使用,我还能再细化一哈,将复制的逻辑可以再次抽离出来,封装一个成一个hook函数useCopy。
实现封装useCopyhook函数
在web中实现复制效果的方法有两种。
优点:
现代化:这是现代浏览器推荐的方式,符合最新的 Web 标准。异步操作:使用Promise,可以更好地处理异步操作和错误处理。更安全:需要用户的明确权限,减少了安全风险。更简洁:代码更简洁,易于理解和维护。
缺点:
兼容性:并非所有浏览器都支持,尤其是一些旧版浏览器。权限问题:需要用户授予剪贴板权限,可能会导致用户体验问题。
优点:
兼容性好:支持较早版本的浏览器,包括一些老旧的浏览器。无需权限:不需要用户授予剪贴板权限,操作更直接。
缺点:
过时:这是一个过时的 API,未来可能会被移除。同步操作:是同步操作,可能会导致阻塞 UI 线程。安全性:存在一定的安全风险,因为它不需要用户的明确权限。
综上,我们navigator.clipboard.writeText(v)的缺点恰好就是doucment.execCommand('copy')的优点,所以我们可以将两种方法其进行结合,首先使用navigator.clipboard.writeText(v)进行复制,若是复制失败后在使用doucment.execCommand('copy')进行复制,最后将复制方法导出,代码如下所示:
import { message } from 'antd';
import { useCallback } from 'react';
function useCopy(): [(str: string) => void] {
const copy = useCallback(async (v: string): Promise<void> => {
if (!v) {
message.warning('复制内容为空!');
return;
}
try {
await navigator.clipboard.writeText(v);
message.success('复制成功!');
} catch (error) { // 复制失败后在使用execCommand复制一次
const textareaC = document.createElement('textarea');
textareaC.setAttribute('readonly', 'readonly'); //设置只读属性防止手机上弹出软键盘
textareaC.value = v;
document.body.appendChild(textareaC); //将textarea添加为body子元素
textareaC.select();
const successful = document.execCommand('copy'); // 执行 copy 操作
if (successful) {
message.success('复制成功!');
document.body.removeChild(textareaC); //移除DOM元素
} else {
message.warning('复制失败,请手动复制!');
}
}
}, []);
return [copy];
}
export default useCopy;
实现CopyText组件
CopyText组件的复制逻辑已经在useCopy函数里面封装好了,然后我们就只需要考虑如何进行组件的展示效果了。
当鼠标指向一个需要复制的元素的时候,最好需要一个hover效果展示具体的内容,点击此元素时候也能直接复制相关内容。
import useCopy from '@/hooks/useCopy';
import { Popover } from 'antd';
type CopyInfo = {
text: string;
title?: string;
children?: React.ReactNode;
};
export default function Index(props: CopyInfo) {
const { text, title, children } = props;
const [copy] = useCopy();
const copyAccessKey = () => {
copy(text);
};
const style = {
cursor: 'pointer',
};
return (
<Popover
content={
<div onClick={copyAccessKey} style={style}>
{text}
div>
}
title={title ?? '复制信息'}
>
<span onClick={copyAccessKey} style={style}>
{children ?? text}
span>
Popover>
);
}
使用及效果
结语
就这样,我们实现了一个复制组件的封装。在这里我们主要考虑的主要是浏览器原生复制的兼容程度,自定义复制逻辑,其次在复制组件中考虑如何需要如何展示数据。