怎样实现复制到剪贴板、禁止复制和粘贴时清洗内容?
先理解原理和示例,再练习完整口述与追问。
回答要点
复制用异步剪贴板 API navigator.clipboard.writeText,需要安全上下文和用户手势,失败时回退到 textarea 加 document.execCommand('copy')(已废弃但仍广泛可用)。禁止复制可用 user-select: none 并拦截 copy 事件,但只能防君子。粘贴时监听 paste 事件读取 clipboardData,只取纯文本,或用 DOMPurify 清洗 HTML 后插入。
原理拆解
navigator.clipboard.readText 读取剪贴板需要权限,浏览器会弹提示,多数场景应监听 paste 事件从事件对象读取,不需要额外权限。富文本编辑器中,用户从 Word 或网页粘贴的内容带有大量样式和潜在危险的标签(script、onerror 属性),直接插入 innerHTML 会导致 XSS。
复制时附加版权信息,可在 copy 事件中修改 clipboardData 并调用 preventDefault。禁止复制无法阻止截图、开发者工具、禁用 JS 或 OCR,敏感内容应依靠权限与水印追溯。
示例与推演
async function copyText(text) {
try {
await navigator.clipboard.writeText(text)
} catch {
const textarea = Object.assign(document.createElement('textarea'), { value: text, readOnly: true })
textarea.style.cssText = 'position:fixed;opacity:0'
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
textarea.remove()
}
}
editor.addEventListener('paste', event => {
event.preventDefault()
const text = event.clipboardData.getData('text/plain')
const selection = window.getSelection()
if (!selection.rangeCount) return
const range = selection.getRangeAt(0)
range.deleteContents()
range.insertNode(document.createTextNode(text))
range.collapse(false)
})
易错点
在非 HTTPS 页面或异步回调中(失去用户手势)调用 clipboard API 会失败;粘贴图片要从 clipboardData.files 读取。不要用正则清洗 HTML。
参考回答可直接练习口述
复制用 navigator.clipboard.writeText,要在 HTTPS 和用户点击中调用,失败时回退到隐藏 textarea 加 execCommand。禁止复制可以 user-select none 加拦截 copy 事件,但截图和开发者工具都绕得过,只能防君子。粘贴我会监听 paste 事件,富文本场景只取纯文本插入,或者用 DOMPurify 清洗 HTML,绝不直接把剪贴板 HTML 写入 innerHTML。