clipboard、clipboard-polyfill、copy-to-clipboard、react-copy-to-clipboard 和 vue-clipboard2 都是用于在浏览器中执行复制文本到系统剪贴板操作的 JavaScript 库。它们解决了现代 Web 应用中常见的“一键复制”需求,但实现方式、兼容性策略、框架集成度和 API 设计各有不同。这些库封装了浏览器原生 Clipboard API 或其降级方案(如使用临时 <textarea>),以提供一致的跨浏览器体验。
在 Web 应用中实现“复制到剪贴板”看似简单,实则充满兼容性陷阱。不同浏览器对 Clipboard API 的支持程度不一,旧版浏览器甚至完全不支持。本文从真实工程角度,对比五款主流剪贴板库的核心机制、适用场景与技术取舍。
所有库最终都依赖两种底层技术之一:
navigator.clipboard.writeText())— 安全、简洁,但需 HTTPS 且部分旧浏览器不支持。<textarea>,选中其内容后调用 document.execCommand('copy')。各库如何选择和封装这两种方式?
clipboard基于 document.execCommand,通过监听 DOM 事件触发复制。要求目标元素通过 data-clipboard-text 或 data-clipboard-target 声明内容。
// HTML
<button id="btn" data-clipboard-text="要复制的内容">复制</button>
// JS
import Clipboard from 'clipboard';
new Clipboard('#btn'); // 自动绑定点击事件
clipboard-polyfill优先使用 navigator.clipboard.writeText(),失败时自动降级到 execCommand 方案。提供统一的 Promise 接口。
import { writeText } from 'clipboard-polyfill';
writeText("要复制的内容")
.then(() => console.log("成功"))
.catch(err => console.error("失败", err));
copy-to-clipboard内部自动检测环境:若支持 navigator.clipboard 则使用,否则回退到 execCommand。提供同步/异步两种调用方式。
import copy from 'copy-to-clipboard';
// 同步(返回布尔值)
const success = copy('要复制的内容');
// 异步(返回 Promise)
const result = await copy('要复制的内容', { format: 'text/plain' });
react-copy-to-clipboard底层依赖 copy-to-clipboard,通过 React 组件封装。
import { CopyToClipboard } from 'react-copy-to-clipboard';
<CopyToClipboard text="要复制的内容" onCopy={() => alert('已复制')}>
<button>复制</button>
</CopyToClipboard>
vue-clipboard2底层依赖 clipboard 库,通过 Vue 指令封装。
// Vue 2 组件
import Vue from 'vue';
import VueClipboard from 'vue-clipboard2';
Vue.use(VueClipboard);
// 模板
<button v-clipboard:copy="'要复制的内容'" v-clipboard:success="onSuccess">复制</button>
clipboard 和 vue-clipboard2 采用声明式设计:在 HTML 中通过属性或指令定义复制内容,JS 只负责初始化。
<!-- clipboard -->
<button data-clipboard-text="固定文本">复制</button>
<!-- vue-clipboard2 -->
<button v-clipboard:copy="fixedText">复制</button>
局限:无法直接复制动态生成的文本(如用户输入、API 返回结果),除非重新渲染 DOM 或手动更新属性。
clipboard-polyfill、copy-to-clipboard 和 react-copy-to-clipboard 支持在任意 JS 逻辑中调用。
// 动态场景:复制当前时间
const now = new Date().toISOString();
// clipboard-polyfill
await writeText(now);
// copy-to-clipboard
copy(now);
// react-copy-to-clipboard(在事件处理器中)
const handleCopy = () => {
// 实际由组件内部调用 copy-to-clipboard
};
clipboard:仅支持 execCommand,在 iOS Safari 等环境中可能失效(因安全限制)。clipboard-polyfill:主动维护,持续适配新浏览器行为(如 Chrome 对 execCommand 的弃用警告),并提供 TypeScript 类型。copy-to-clipboard:覆盖 IE9+,但在严格 CSP 环境下可能因动态创建 DOM 而受阻。react-copy-to-clipboard:兼容性取决于底层 copy-to-clipboard。vue-clipboard2:兼容性取决于底层 clipboard,且因停止维护,未适配现代浏览器变更。⚠️ 注意:
vue-clipboard2的 GitHub 仓库已归档,明确标注 “Vue 2 only”,Vue 3 项目绝对不应使用。clipboard虽未正式废弃,但多年无更新,存在兼容性风险。
clipboard-polyfill 和 copy-to-clipboard(异步模式)通过 Promise 捕获错误,可区分“用户拒绝”和“技术失败”。
writeText(content).catch(e => {
if (e.name === 'NotAllowedError') {
// 用户未授予权限
}
});
clipboard 和 vue-clipboard2 通过事件回调提供成功/失败状态,但无法获取具体错误原因。
// clipboard
clipboard.on('error', e => console.log('复制失败'));
react-copy-to-clipboard 通过 onCopy 回调传递结果。
<CopyToClipboard onCopy={(text, result) => {
if (!result) alert('失败');
}} />
| 库 | 原生 JS | React | Vue 2 | Vue 3 |
|---|---|---|---|---|
clipboard | ✅ | ⚠️ 需手动集成 | ⚠️ 需手动集成 | ⚠️ 需手动集成 |
clipboard-polyfill | ✅ | ✅ | ✅ | ✅ |
copy-to-clipboard | ✅ | ✅ | ✅ | ✅ |
react-copy-to-clipboard | ❌ | ✅ | ❌ | ❌ |
vue-clipboard2 | ❌ | ❌ | ✅ | ❌ |
clipboard-polyfill — 现代 API 语义、主动维护、Promise 支持、类型安全。copy-to-clipboard — 无依赖、小体积、同步/异步双模式。react-copy-to-clipboard;否则直接用 copy-to-clipboard 或 clipboard-polyfill。vue-clipboard2 可用,但需注意其已停止维护;更推荐直接集成 copy-to-clipboard。clipboard(无维护)和 vue-clipboard2(Vue 3 不兼容且已归档)。无论选用哪个库,建议封装一层统一接口处理权限和降级:
// 使用 clipboard-polyfill
import { writeText } from 'clipboard-polyfill';
export async function safeCopy(text) {
try {
await writeText(text);
return { success: true };
} catch (err) {
// 处理用户拒绝或浏览器限制
if (err.name === 'NotAllowedError') {
return { success: false, reason: 'user-denied' };
}
return { success: false, reason: 'technical-error' };
}
}
// 在 React/Vue/原生中统一调用
const handleClick = async () => {
const result = await safeCopy(dynamicContent);
if (!result.success) {
// 显示友好提示
alert('请手动复制:' + dynamicContent);
}
};
剪贴板操作虽小,却直接影响用户体验。选择有维护、有降级、有错误反馈的方案,才能避免“复制按钮点不动”的尴尬。
选择 react-copy-to-clipboard 如果你在 React 项目中需要将复制功能作为组件使用,并希望自动处理状态反馈(如是否已复制)。它封装了底层复制逻辑,提供 <CopyToClipboard> 组件,适合 JSX 声明式开发,但仅限 React 生态。
选择 clipboard 如果你需要一个轻量、无依赖、基于 DOM 事件驱动的通用库,适用于原生 JavaScript 项目或任何框架。它通过 data-attribute 声明式绑定目标元素,适合静态内容复制场景,但不支持动态文本或程序化调用(除非手动触发事件)。注意:该库已不再积极维护,新项目应谨慎评估。
选择 clipboard-polyfill 如果你追求现代 Clipboard API 的语义一致性,并希望在旧浏览器中自动回退到兼容方案。它提供统一的 Promise 接口,支持文本和富文本(HTML)复制,且主动维护。适合需要程序化控制、类型安全和未来兼容性的项目。
选择 vue-clipboard2 如果你在 Vue 2 项目中希望通过指令(如 v-clipboard)快速集成复制功能。它基于 clipboard 库封装,提供 Vue 指令和方法调用两种方式。注意:该库明确标注为 Vue 2 专用,且仓库已归档,Vue 3 项目不应使用。
选择 copy-to-clipboard 如果你需要最简化的函数式 API 来程序化复制任意字符串,且不关心声明式绑定。它体积小、无依赖、支持 Promise 和回调两种风格,兼容性覆盖 IE9+。适合 React、Vue 等框架中通过逻辑层直接调用的场景。
Copy to clipboard React component
Based on copy-to-clipboard
Would try to use execCommand with fallback to IE specific clipboardData interface and finally, fallback to simple prompt with proper text content & 'Copy to clipboard: Ctrl+C, Enter'

yarn add react-copy-to-clipboard
npm install --save react-copy-to-clipboard
Don't forget to manually install peer dependencies (react) if you use npm@3.
https://nkbt.github.io/react-copy-to-clipboard
https://codepen.io/nkbt/pen/eNPoQv
import React from 'react';
import ReactDOM from 'react-dom';
import {CopyToClipboard} from 'react-copy-to-clipboard';
class App extends React.Component {
state = {
value: '',
copied: false,
};
render() {
return (
<div>
<input value={this.state.value}
onChange={({target: {value}}) => this.setState({value, copied: false})} />
<CopyToClipboard text={this.state.value}
onCopy={() => this.setState({copied: true})}>
<span>Copy to clipboard with span</span>
</CopyToClipboard>
<CopyToClipboard text={this.state.value}
onCopy={() => this.setState({copied: true})}>
<button>Copy to clipboard with button</button>
</CopyToClipboard>
{this.state.copied ? <span style={{color: 'red'}}>Copied.</span> : null}
</div>
);
}
}
const appRoot = document.createElement('div');
document.body.appendChild(appRoot);
ReactDOM.render(<App />, appRoot);
text: PropTypes.string.isRequiredText to be copied to clipboard
onCopy: PropTypes.funcOptional callback, will be called when text is copied
onCopy(text, result)
result (bool): Returns true if copied successfully, else false.
options: PropTypes.shape({debug: bool, message: string, format: string})Optional copy-to-clipboard options.
See API docs for details
children: PropTypes.element.isRequiredCopyToClipboard is a simple wrapping component, it does not render any tags, so it requires the only child element to be present, which will be used to capture clicks.
<CopyToClipboard text="Hello!">
<button>Copy to clipboard</button>
</CopyToClipboard>
Currently is being developed and tested with the latest stable Node on OSX.
To run example covering all CopyToClipboard features, use yarn start, which will compile example/Example.js
git clone git@github.com:nkbt/react-copy-to-clipboard.git
cd react-copy-to-clipboard
yarn install
yarn start
# then
open http://localhost:8080
# to run Biome check
yarn lint
# to run tests
yarn test
MIT