文章目录
1. 问题引入
在浏览某些文章时,无论是CTRL + C
复制,还是右键复制,都会弹出充值页面(常见于某某文库),虽然说可以截图后进行文字识别,但有些文章篇幅较长,文字识别不是长久之计
作为一名优秀的复制粘贴工程师,是不能忍受连复制文字都要收钱的
2. 禁止复制文字的原理
复制文字之后弹出充值页面是怎么做到的呢,本质上就是监听了复制事件
2.1 准备工作
我们准备一个简单的HTML页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>copy</title>
</head>
<body>
<div>
<p>你来自于南方的村落</p>
<p>来自粗糙的双手</p>
<p>你站在楼宇的缝隙</p>
<p>可你没有退缩</p>
<p>我来自于北方的春天</p>
<p>来自一步一回首</p>
<p>背后有告别的路口</p>
<p>温暖每个日落</p>
<p>当家乡入冬的时候</p>
<p>列车到站以后</p>
<p>小时候的风再吹过</p>
<p>回忆起单纯的快乐</p>
<p>在熟悉的街头</p>
<p>有人会用所有的温柔</p>
<p>喊出你的名字</p>
<p>离家的人啊我敬你一杯酒</p>
<p>敬你的沉默和每一声怒吼</p>
<p>敬你弯着腰上山往高处走</p>
<p>头顶苍穹努力地生活</p>
</div>
<script>
document.addEventListener('copy', function (event) {
console.log(event)
})
</script>
</body>
</html>
正常情况下,无论是CTRL + C复制,还是右键复制,都是会触发复制事件的
2.2 如何阻止用户复制文字
怎么阻止用户复制文字呢?我们只需要阻止复制事件的默认行为就可以了
<script>
document.addEventListener('copy', function (event) {
console.log(event)
// 阻止复制事件的默认行为
event.preventDefault()
})
</script>
阻止复制事件的默认行为之后,即使用户进行了复制操作,剪贴板中也不会有对应的内容(按下Win + V
快捷键键可以查看剪贴板内容)
2.3 在复制内容后面加上版权信息
拿到event对象之后,我们可以实现一些更好玩的效果,例如用户进行复制操作后,在复制内容后面加上版权信息
复制CSDN上的文章时,复制内容后面会附带版权信息,就是利用event对象实现的
<script>
document.addEventListener('copy', function (event) {
// 阻止复制事件的默认行为
event.preventDefault()
// 获取选中的文本
const selection = document.getSelection().toString()
// 设置要添加的版权信息
const copyrightText = '\n\n版权所有 © 聂可以'
// 将版权信息添加到选中的文本后面
const textToCopy = selection + copyrightText;
// 使用 Clipboard API 写入新的文本
event.clipboardData.setData('text/plain', textToCopy)
})
</script>
3. 如何解除禁止复制的限制
我们回到正题,知道了禁止复制的原理之后,怎么解除浏览器中禁止复制的限制呢?
3.1 案例演示
第一步:按下F12打开浏览器的控制台,点击选择元素按钮(也可以直接按下CTRL + SHIFT + C
快捷键)
第二步:鼠标左键点击要复制的内容
点击要复制的内容后对应的标签会有高亮背景,接着我们点击事件监听器一栏,再点开copy事件
点击删除图标,把所有监听copy事件的侦听器全删掉,就能愉快地复制所有内容了(记得把上级元素也勾上)
3.2 动手实践
看到这里的同学,赶紧找一个复制文字要付费的网页动手实践一下吧
或者也可以直接在本文章上进行测试,看看能不能去掉CSDN在复制内容后面添加的版权信息(记得复制大量文字,仅复制少量文字时不会在复制内容后面加上版权信息)
3.3 使用浏览器插件解除禁止复制限制
其实,我们能想到的,大概率已经有人想到了。没错,已经有大神开发出了能解除禁止复制限制的浏览器插件
第一步:打开浏览器的插件页面
点击获取 Microsoft Edge 扩展
第二步:在右上角搜索SuperCopy 超级复制,点击第一个
SuperCopy 超级复制
接着点击右上角的获取按钮(由于我已经装过了,所以获取按钮变成了删除按钮)
第三步:安装完成后,再次打开浏览器的插件页面,将刚才安装的SuperCopy 超级复制
插件固定到工具栏
第四步:打开某个网页,点击SuperCopy 超级复制
插件的图标
点击破解禁止复制
,就能够愉快地复制文字了
开启破解禁止复制之后,插件的图标也会变成蓝色(关闭破解复制后会重新刷新页面)
4. 与剪贴板相关的API
4.1 与剪贴板相关的API的应用场景
我们来看一下粘贴板的应用场景:
- 在网页中粘贴一张图片,图片能够立即回显到页面上
- 打开某个程序时,程序会将剪贴板中的内容读取出来,跳转到对应的商品页面或视频页面(当好友在微信分享了一个某音、某手、某多多或某东的链接给你时,复制链接后,打开对应的程序,就能够跳转到详情页面)
除了上述应用场景之外,上面演示的禁止复制文字也是利用了与剪贴板相关的API
4.2 Clipboard API
剪贴板,可以理解为操作系统为我们开辟的一块独立内存空间
- 当进行复制操作的时候,就相当于往这个内存空间里面写入数据,可以写入文字、图片,也可以写入文件
- 当进行粘贴操作的时候,就是从这个内存空间里面把数据读取出来,显示在某一个地方
浏览器为我们提供了一套与剪贴板相关的API,这套API被称为Clipboard API,我们可以在浏览器的控制台中查看
navigator.clipboard
navigator.clipboard
对象提供了用于读写系统剪贴板的接口。以下是 Clipboard
对象中的四个主要方法及其含义:
read()
: 这个方法返回一个Promise
,该Promise
解析为一个ClipboardItem
对象数组,表示剪贴板上的数据。ClipboardItem
对象可以包含不同类型的数据,比如文本、图像等。这个方法通常用于读取剪贴板上的非文本内容。readText()
: 这个方法返回一个Promise
,该Promise
解析为剪贴板上的文本内容。如果剪贴板上没有文本内容,则解析为空字符串。这个方法用于读取剪贴板上的文本数据write()
: 这个方法接收一个ClipboardItem
对象数组作为参数,并尝试将它们写入剪贴板。这个方法用于将复杂的数据类型(如文本、图像等)写入剪贴板writeText()
: 这个方法接收一个字符串作为参数,并将其作为文本写入剪贴板。如果操作成功,该方法返回一个Promise
,该Promise
在写入完成后解析为undefined
。这个方法用于将文本数据写入剪贴板
为什么readXXX方法返回的是一个Promise对象呢,因为剪贴板涉及到用户的隐私,浏览器会询问用户是否允许访问粘贴板,只有用户允许访问之后,Promise才会执行完成,执行完成后会回传从剪贴板中读取到的内容
示例代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Clipboard-copy</title>
</head>
<body>
<div class="editor">
</div>
<script>
navigator.clipboard.readText().then((text) => {
document.querySelector('.editor').innerHTML = text
})
</script>
</body>
</html>
4.3 案例演示
我们来做一个案例,将剪贴板中的图片读取出来,回显到页面上
我们准备一个div标签,为这个div标签加上contenteditable属性,使这个div标签变成一个文本编辑器(毕竟图片不能放到input标签里面,也不能放到textArea标签里面)
我们监听这个文本编辑器的粘贴事件,如果用户粘贴的是纯文本,我们不做额外处理,我们只处理粘贴内容的是文件的情况
拿到图片文件后,不仅可以回显到页面上(其实div标签加上contenteditable属性后,即使不做额外处理,浏览器也能够回显用户粘贴的图片),还可以上传到服务器
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Clipboard-paste</title>
<style>
/* 设置编辑器的样式 */
.editor {
min-height: 300px; /* 编辑器的最小高度 */
border: 3px solid #4CAF50; /* 编辑器的边框 */
padding: 20px; /* 内边距 */
font-family: 'Arial', sans-serif; /* 字体 */
font-size: 16px; /* 字体大小 */
color: #333; /* 文字颜色 */
background-color: #FAFAFA; /* 背景颜色 */
resize: vertical; /* 允许垂直方向调整大小 */
outline: none; /* 移除焦点时的轮廓线 */
transition: all 0.3s ease; /* 过渡效果 */
}
/* 编辑器获得焦点时的样式 */
.editor:focus {
border-color: #2196F3; /* 焦点时的边框颜色 */
box-shadow: 0 0 10px #2196F3; /* 焦点时的阴影效果 */
}
</style>
</head>
<body>
<!-- 创建一个可编辑的 div 元素,用作文本编辑器 -->
<div class="editor" contenteditable="true">
<!-- 用户可以在这里粘贴内容 -->
</div>
<script>
// 获取编辑器元素
const editor = document.querySelector('.editor')
// 为编辑器添加 paste 事件监听器,当用户粘贴内容时触发
editor.addEventListener('paste', (pasteEvent) => {
// 检查剪贴板数据中是否有文件
if (pasteEvent.clipboardData.files.length > 0) {
// 阻止默认的粘贴行为,因为我们想要自定义处理文件
pasteEvent.preventDefault()
// 获取剪贴板中的第一个文件
const file = pasteEvent.clipboardData.files[0]
// 创建一个新的 FileReader 对象,用于读取文件内容
const reader = new FileReader()
// 当文件读取完成时触发的事件处理器
reader.onload = (loadEvent) => {
// 创建一个新的 img 元素,用于显示图片
const img = document.createElement('img')
// 设置 img 元素的 src 属性为读取到的文件数据
img.src = loadEvent.target.result.toString()
// 将 img 元素添加到编辑器中
editor.appendChild(img)
}
// 读取文件内容为 Data URL
reader.readAsDataURL(file)
}
})
</script>
</body>
</html>