自己最近刚好写了一篇这样的文章:能力有限,如有错误,请大家批评指正
查看原文请点击这里:👉复制文章内容时添加版权信息
在复制有些网站的文章时,通常会发现,复制的内容还带了一个“小尾巴”,上边附带着版权信息。
例如:
作者:CoderLeiShuo
链接:https://juejin.im/user/4160207732875736
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在本篇文章中,尝试来实现一下这种效果。
大致原理就是在用户复制时,获取用户选中的将要复制的内容,然后再加上版权信息即可。
window.getSelection()方法如何获取用户复制的内容呢?我们可以通过window.getSelection()方法,它返回一个Selection对象,表示用户选择的文本范围或光标的当前位置。当然,你也可以用document.getSelection,它们二者等价。

比如将光标置入上图中的搜索框,然后在控制台输入window.getSelection()。返回的Selection对象如下图所示:

我们最终要获取的是选中区域的纯文本,而不是一个Seletion对象。因此需要将Selection对象转换成字符串,可以通过拼接一个空字符串或使用String.toString()方法。
let selObj = window.getSelection();
let selectedTxt = selObj + '';
// 或者
let selectedTxt = selObj.toString();
我们在网页中尝试一下:

如上图所示:我们选择了网页中的部分内容,在控制台输入相关代码,看能否正确获取到选择内容的纯文本

可以看到,我们已经获取到了所选择的内容。
window.getSelection()在IE8及以下的浏览器上不支持
element.oncopy事件上一步操作中,我们已经成功获取到了选区中的文本内容。现在我们要开始实现复制时给复制的内容添加信息的效果了。
因此我们需要给element.oncopy事件绑定相应的函数,实现相应功能。
oncopy属性用来获取或设置当前元素的copy事件的事件处理函数。注意,oncopy属性是可以给其他元素进行设置的,不要因为我们一般都设置在window或document上,就认为它只能给它们设置。
我们先来看一个MDN上的例子:
<html>
<head>
<title>oncopy示例演示</title>
<script>
function log(txt)
{
// 以txt的值创建一个文本节点,作为子节点,追加到textarea元素中
document.getElementById("log").appendChild(document.createTextNode(txt + "\n"));
}
</script>
</head>
<body>
<div oncopy="log('复制被阻止!'); return false;">试着复制这句话!</div>
<h3>Log</h3>
<textarea rows="15" cols="80" id="log" readonly="true"></textarea>
</body>
</html>
当你尝试复制“试试复制这句话!”时,将会触发oncopy()函数,在oncopy()函数中,以传入的txt的值创建了一个文本节点,作为子节点,追加到textarea元素上了。因此,textarea将会显示'复制被阻止'字样!

并且由于return false;语句使得复制的默认行为被取消,因此没有返回复制的内容。
通过前面内容的学习,我们可以做第一次尝试。通过window.selection()方法获取选中的内容,然后为oncopy绑定自定义的事件,在自定义事件中,把获取到的选区内容和我们的"小尾巴"信息进行拼接。
代码如下:
<!-- 第一次实现 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<p>在 JavaScript中,当一个对象被传递给期望字符串作为参数的函数中时(如 window.alert 或 document.write),对象的toString()方法会被调用,然后将返回值传给该函数。</p>
<p>实现很简单:取消默认复制之后,主要是在被复制的内容后面添加信息,然后根据 clipboardData 的 setData()方法将信息写入剪贴板</p>
<script>
document.oncopy = function () {
let selObj = window.getSelection();
// IE8及更早不支持window.getSelection
if (typeof selObj == 'undefined') return;
let selectedText = selObj + '';
// 如果选中文字内容小于30个字符,则不做任何操作
if (selectedText.length < 30) return;
let copytext = selectedText + 'CoderLeiShuo';
console.log(copytext);
}
</script>
</body>
</html>

可以看到,通过给oncopy绑定自定义的事件,在事件代码执行后,输出了选区文本和'CoderLeiShuo'拼接后的字符串。

那么,如果我们将copytext返回出去,是不是就可以实现了呢?
于是,函数中加入return copytext;语句。来看一下结果:

很不幸,粘贴的内容中还是选中的那些文字,并不是我们需要的拼接后的字符串
原因有两点:
oncopy绑定的函数中,我们返回context是没有用的,而应该返回false,代表取消复制的默认行为。否则,无论你拼接什么的内容,剪贴板里的内容仍然只有你复制的那些。clipboardData对象取消默认的复制行为很好办,接下来,我们要详细研究一下剪贴板了。
clipboardData对象:用于访问及修改剪贴板中的数据
不同浏览器,所属的对象不同:在 IE 中这个对象是window对象的属性,在Chrome、Safari和Firefox中,这个对象是相应的event对象的属性。所以我们在使用的时候,需要做一下如下兼容
document.oncopy = e => {
let clipboardData = e.clipboardData || window.clipboardData;
// 获取clipboardData对象 + do something
}
该对象有三个方法:getData()、setData()、clearData()
getData()方法getData()方法接受一个format参数,即要取得的数据的格式。数据类型有:text/plain、text/uri-list。
setData()方法setData()方法授受两个参数,一个是format参数,代表数据类型。第二个参数代表要放入剪贴板中的文本内容。这里我们可以指定format参数为text/plain,代表纯文本。
clearData()方法clearData()方法接受一个可选参数format,代表要删除的数据类型。如果此参数为空字符串或未提供,则删除所有类型的数据。
结合上面的内容,我们来做二次尝试。具体代码如下:
<!-- 第二次实现 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
p {
color: red;
font-size: 20px;
}
</style>
</head>
<body>
<p>在 JavaScript中,当一个对象被传递给期望字符串作为参数的函数中时(如 window.alert 或 document.write),对象的toString()方法会被调用,然后将返回值传给该函数。</p>
<p>实现很简单:取消默认复制之后,主要是在被复制的内容后面添加信息,然后根据 clipboardData 的 setData()方法将信息写入剪贴板</p>
<script>
document.oncopy = function (e) {
// 获取选区对象
let selObj = window.getSelection();
// IE8及更早不支持window.getSelection
if (typeof selObj == 'undefined') return false;
// 获取clipboardData对象
// Chrome\Safari\Firefox浏览器中,这个对象是event对象的属性
// IE浏览器中,它是window对象的属性
let clipboardData = e.clipboardData || window.clipboardData;
// 获取选区文本内容
let selectedText = selObj + '';
let copytext;
// 如果选中文字内容小于30个字符,则不做任何操作
if (selectedText.length < 30) {
copytext = selectedText;
} else {
copytext = selectedText +
'\n\n\n' +
'作者:CoderLeiShuo\n' +
'链接:' + location.href + '\n' +
'来源:掘金\n' +
'著作权归作者所有。商业转载请联系作者获取授权,非商业转载请注明出处。';
}
// setData(format,text)用于设置剪贴板内容
clipboardData.setData('text/plain', copytext);
// 取消默认的复制事件
return false;
// e.preventDefault()亦可
}
</script>
</body>
</html>
来看一下效果:

至此,我们已经实现了基本的功能,但是目前的代码还没有兼容低版本的IE浏览器,并且还没有实现带格式复制的功能。后续将继续进行完善。
本篇文章在写作过程中,参考了以下文章的内容。
Most helpful comment