需求背景与实现思路
在表单类页面中,我们常常需要让用户快速复制输入框内的内容,比如订单号、验证码、配置参数等。当页面存在多个这类输入框时,逐个编写复制逻辑会非常繁琐。结合Chakra UI的组件特性,我们可以封装一个通用的复制按钮组件,通过接收输入框的引用或内容值,实现一键复制,同时复用样式和交互逻辑。

核心依赖与API说明
实现复制功能主要依赖两个核心部分:一是浏览器的navigator.clipboard.writeText API,用于把文本内容写入剪贴板;二是Chakra UI提供的useToast钩子,用于复制成功或失败时给用户反馈提示。
navigator.clipboard.writeText:浏览器原生剪贴板写入API,支持异步操作,兼容性覆盖大部分现代浏览器useToast:Chakra UI的提示钩子,可快速生成轻量级的反馈通知Input、Button、HStack:Chakra UI的基础组件,用于构建输入框和按钮布局
通用复制按钮组件封装
首先封装一个可复用的复制按钮组件,接收要复制的内容作为参数,点击时执行复制逻辑并给出提示。
import { useToast } from '@chakra-ui/react';
import { Button } from '@chakra-ui/react';
import { CopyIcon } from '@chakra-ui/icons';
const CopyButton = ({ copyText, size = 'sm' }) => {
const toast = useToast();
const handleCopy = async () => {
if (!copyText) {
toast({
title: '复制失败',
description: '没有可复制的内容',
status: 'warning',
duration: 2000,
isClosable: true,
});
return;
}
try {
await navigator.clipboard.writeText(copyText);
toast({
title: '复制成功',
description: '内容已复制到剪贴板',
status: 'success',
duration: 2000,
isClosable: true,
});
} catch (err) {
toast({
title: '复制失败',
description: '请手动选择内容复制',
status: 'error',
duration: 2000,
isClosable: true,
});
}
};
return (
<Button
size={size}
leftIcon={<CopyIcon />}
onClick={handleCopy}
variant="outline"
colorScheme="blue"
>
复制
</Button>
);
};
export default CopyButton;
多个输入框的复制功能实现
接下来在页面中使用封装好的复制按钮,为每个输入框搭配对应的复制功能,这里以三个不同用途的输入框为例。
import { Input, HStack, VStack, Text, Box } from '@chakra-ui/react';
import CopyButton from './CopyButton';
import { useState } from 'react';
const MultiInputCopyPage = () => {
const [orderNo, setOrderNo] = useState('20240520123456');
const [verifyCode, setVerifyCode] = useState('8A3B9C');
const [configParam, setConfigParam] = useState('timeout=3000&retry=3');
return (
<Box p={6} maxW="600px" mx="auto">
<Text fontSize="xl" fontWeight="bold" mb={6}>
多输入框复制功能示例
</Text>
<VStack spacing={4} align="stretch">
{/* 订单号输入框 */}
<HStack>
<Text w="100px" textAlign="right">
订单号:
</Text>
<Input
value={orderNo}
onChange={(e) => setOrderNo(e.target.value)}
readOnly
/>
<CopyButton copyText={orderNo} />
</HStack>
{/* 验证码输入框 */}
<HStack>
<Text w="100px" textAlign="right">
验证码:
</Text>
<Input
value={verifyCode}
onChange={(e) => setVerifyCode(e.target.value)}
readOnly
/>
<CopyButton copyText={verifyCode} />
</HStack>
{/* 配置参数输入框 */}
<HStack>
<Text w="100px" textAlign="right">
配置参数:
</Text>
<Input
value={configParam}
onChange={(e) => setConfigParam(e.target.value)}
readOnly
/>
<CopyButton copyText={configParam} />
</HStack>
</VStack>
</Box>
);
};
export default MultiInputCopyPage;
进阶优化方案
如果输入框数量非常多,还可以进一步优化实现方式:
- 将输入框和复制按钮封装成一个组合组件,进一步减少重复代码
- 支持复制按钮的自定义样式,比如通过props传入
colorScheme、variant等属性 - 添加复制前的预处理逻辑,比如去掉内容中的空格、特殊符号等
- 对不支持
navigator.clipboard的旧浏览器做降级处理,使用document.execCommand('copy')兼容
常见问题处理
在实际使用中可能会遇到两个问题:一是部分浏览器要求复制操作必须由用户主动触发,所以复制逻辑必须绑定在按钮的点击事件中,不能自动执行;二是如果输入框的内容是可编辑的,需要注意复制的是当前最新的值,而不是初始值,上面的示例中通过value和onChange绑定了状态,已经避免了这个问题。