pin_drop当前位置:知识文库 ❯ 图文
HTML5 API:HTML5 Clipboard API - 完整教程与代码示例
一、教程简介
Clipboard API 提供了在 Web 应用中读写系统剪贴板的能力,允许开发者以编程方式复制文本、图片等数据到剪贴板,或从剪贴板读取内容。该 API 替代了传统的 document.execCommand('copy') 方法,提供了更安全、更强大的异步剪贴板操作接口,广泛应用于复制按钮、粘贴处理、富文本编辑等场景。
二、核心概念
API 概览
权限模型
ClipboardEvent
三、语法与用法
写入文本
代码示例
// 异步写入
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
console.log('复制成功');
} catch (err) {
console.error('复制失败:', err);
}
}读取文本
代码示例
async function pasteText() {
try {
const text = await navigator.clipboard.readText();
console.log('粘贴内容:', text);
} catch (err) {
console.error('读取失败:', err);
}
}写入图片
代码示例
async function copyImage(blob) {
try {
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
} catch (err) {
console.error('复制图片失败:', err);
}
}监听剪贴板事件
代码示例
document.addEventListener('copy', function(e) {
e.preventDefault();
e.clipboardData.setData('text/plain', '自定义复制内容');
});
document.addEventListener('paste', function(e) {
const text = e.clipboardData.getData('text/plain');
console.log('粘贴:', text);
});四、代码示例
示例一:剪贴板操作工具
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Clipboard API - 剪贴板工具</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
background: #f5f7fa;
min-height: 100vh;
padding: 30px 20px;
}
.container { max-width: 640px; margin: 0 auto; }
h1 { font-size: 24px; color: #2d3436; margin-bottom: 8px; }
.desc { color: #636e72; font-size: 14px; margin-bottom: 24px; }
.card {
background: #fff;
border-radius: 12px;
padding: 24px;
margin-bottom: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
}
.card h2 { font-size: 16px; color: #2d3436; margin-bottom: 16px; }
textarea {
width: 100%;
padding: 12px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 14px;
min-height: 100px;
resize: vertical;
outline: none;
font-family: inherit;
}
textarea:focus { border-color: #0984e3; }
.btn-group { display: flex; gap: 10px; margin-top: 12px; flex-wrap: wrap; }
button {
padding: 8px 18px;
border: none;
border-radius: 8px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-blue { background: #0984e3; color: #fff; }
.btn-blue:hover { background: #0770c2; }
.btn-green { background: #00b894; color: #fff; }
.btn-green:hover { background: #00a381; }
.btn-orange { background: #fdcb6e; color: #333; }
.btn-orange:hover { background: #e5b85c; }
.toast {
position: fixed;
top: 20px;
right: 20px;
padding: 12px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
color: #fff;
z-index: 9999;
transform: translateX(120%);
transition: transform 0.3s ease;
}
.toast.show { transform: translateX(0); }
.toast.success { background: #00b894; }
.toast.error { background: #e17055; }
.copy-items { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.copy-item {
padding: 12px;
border: 1px solid #eee;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
}
.copy-item:hover { border-color: #0984e3; background: #f0f7ff; }
.copy-item-label { font-size: 12px; color: #999; margin-bottom: 4px; }
.copy-item-value { font-size: 14px; color: #333; font-weight: 500; word-break: break-all; }
.history-list { max-height: 200px; overflow-y: auto; }
.history-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid #f0f0f0;
font-size: 13px;
}
.history-text { flex: 1; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-right: 12px; }
.history-time { color: #999; font-size: 11px; white-space: nowrap; }
</style>
</head>
<body>
<div class="container">
<h1>剪贴板操作工具</h1>
<p class="desc">使用 Clipboard API 进行复制、粘贴和剪贴板事件监听。</p>
<div class="card">
<h2>复制文本</h2>
<div class="copy-items">
<div class="copy-item" onclick="copyText('hello@example.com')">
<div class="copy-item-label">邮箱</div>
<div class="copy-item-value">hello@example.com</div>
</div>
<div class="copy-item" onclick="copyText('13800138000')">
<div class="copy-item-label">电话</div>
<div class="copy-item-value">13800138000</div>
</div>
<div class="copy-item" onclick="copyText('https://example.com')">
<div class="copy-item-label">网址</div>
<div class="copy-item-value">https://example.com</div>
</div>
<div class="copy-item" onclick="copyText('npm install clipboard')">
<div class="copy-item-label">命令</div>
<div class="copy-item-value">npm install clipboard</div>
</div>
</div>
</div>
<div class="card">
<h2>自定义复制</h2>
<textarea id="copyInput" placeholder="输入要复制的文本..."></textarea>
<div class="btn-group">
<button class="btn-blue" onclick="copyCustom()">复制文本</button>
<button class="btn-green" onclick="pasteCustom()">粘贴到下方</button>
</div>
</div>
<div class="card">
<h2>粘贴区域</h2>
<textarea id="pasteOutput" placeholder="粘贴的内容会显示在这里..." readonly></textarea>
<div class="btn-group">
<button class="btn-orange" onclick="document.getElementById('pasteOutput').value=''">清空</button>
</div>
</div>
<div class="card">
<h2>操作历史</h2>
<div class="history-list" id="historyList">
<div style="text-align:center;color:#999;padding:20px;font-size:13px;">暂无操作记录</div>
</div>
</div>
</div>
<div class="toast" id="toast"></div>
<script>
let history = [];
async function copyText(text) {
try {
await navigator.clipboard.writeText(text);
showToast('复制成功!', 'success');
addHistory('复制', text);
} catch (err) {
fallbackCopy(text);
}
}
async function copyCustom() {
const text = document.getElementById('copyInput').value;
if (!text) { showToast('请输入文本', 'error'); return; }
await copyText(text);
}
async function pasteCustom() {
try {
const text = await navigator.clipboard.readText();
document.getElementById('pasteOutput').value = text;
showToast('粘贴成功!', 'success');
addHistory('粘贴', text);
} catch (err) {
showToast('粘贴失败:' + err.message, 'error');
}
}
function fallbackCopy(text) {
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.cssText = 'position:fixed;left:-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
document.execCommand('copy');
showToast('复制成功(降级方式)', 'success');
addHistory('复制', text);
} catch (err) {
showToast('复制失败', 'error');
}
document.body.removeChild(textarea);
}
function showToast(message, type) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.className = 'toast ' + type + ' show';
setTimeout(() => toast.classList.remove('show'), 2500);
}
function addHistory(action, text) {
history.unshift({ action, text, time: new Date().toLocaleTimeString('zh-CN') });
if (history.length > 20) history.pop();
renderHistory();
}
function renderHistory() {
const list = document.getElementById('historyList');
list.innerHTML = history.map(function (item) {
const display = item.text.length > 40 ? item.text.substring(0, 40) + '...' : item.text;
return '<div class="history-item"><span class="history-text" title="' + escapeHtml(item.text) + '">[' + item.action + '] ' + escapeHtml(display) + '</span><span class="history-time">' + item.time + '</span></div>';
}).join('');
}
function escapeHtml(str) { const div = document.createElement('div'); div.textContent = str; return div.innerHTML; }
document.addEventListener('paste', function (e) {
const text = e.clipboardData.getData('text/plain');
if (text) { addHistory('粘贴事件', text); }
});
</script>
</body>
</html>五、浏览器兼容性
六、注意事项与最佳实践
1. 安全限制
-
所有 Clipboard API 调用必须由用户操作触发
-
read和readText需要用户授权 -
必须在安全上下文(HTTPS)中使用
2. 降级方案
代码示例
async function copyToClipboard(text) {
if (navigator.clipboard && navigator.clipboard.writeText) {
try {
await navigator.clipboard.writeText(text);
return true;
} catch (e) { /* 降级 */ }
}
// 降级到 execCommand
const textarea = document.createElement('textarea');
textarea.value = text;
textarea.style.cssText = 'position:fixed;opacity:0';
document.body.appendChild(textarea);
textarea.select();
const result = document.execCommand('copy');
document.body.removeChild(textarea);
return result;
}3. 复制图片
代码示例
async function copyCanvasImage(canvas) {
try {
const blob = await new Promise(resolve => canvas.toBlob(resolve));
await navigator.clipboard.write([
new ClipboardItem({ 'image/png': blob })
]);
} catch (err) {
console.error('复制图片失败:', err);
}
}七、代码规范示例
代码示例
class ClipboardHelper {
static async writeText(text) {
if (navigator.clipboard?.writeText) {
await navigator.clipboard.writeText(text);
return true;
}
return this._fallbackWrite(text);
}
static async readText() {
if (navigator.clipboard?.readText) {
return await navigator.clipboard.readText();
}
throw new Error('Clipboard readText 不可用');
}
static async write(items) {
if (navigator.clipboard?.write) {
await navigator.clipboard.write(items);
return true;
}
throw new Error('Clipboard write 不可用');
}
static _fallbackWrite(text) {
const el = document.createElement('textarea');
el.value = text;
el.style.cssText = 'position:fixed;opacity:0;left:-9999px';
document.body.appendChild(el);
el.select();
const ok = document.execCommand('copy');
document.body.removeChild(el);
return ok;
}
}八、常见问题与解决方案
常见问题
Clipboard API 在 HTTP 下不可用?
Clipboard API 要求安全上下文(HTTPS 或 localhost)。HTTP 环境下需降级为 execCommand。
读取剪贴板时弹出权限提示?
readText 和 read 需要用户授权。可以先检查权限状态:const permission = await navigator.permissions.query({ name: 'clipboard-read' })。
如何复制富文本?
使用 ClipboardEvent 拦截复制事件,通过 e.clipboardData.setData('text/html', '<b>粗体文本</b>') 设置富文本内容。
九、总结
Clipboard API 提供了现代化的异步剪贴板操作接口,支持文本和图片的读写。使用时需注意安全限制(HTTPS、用户操作触发)、权限管理(读取需授权)和降级方案(execCommand)。通过 ClipboardEvent 可以拦截和自定义复制/粘贴行为。封装工具类可以简化 API 调用并自动处理兼容性问题。
本文涉及AI创作
内容由AI创作,请仔细甄别