我们在访问慕课网的时候,可以不经意中发现,复制进剪贴板的信息被修改了,加入了一些版权信息什么的,比如下面这样:
可能你可以不假思索的想到,获取剪贴板的信息,再做一定修改,再重新设置剪贴板的信息。这在IE下是完全可行的。
IE有一个clipboardData对象。通过clipboardData对象可以取到相应的数据。
window.clipboardData.getData("Text");
比如说下面这样:
然而这样实际上非常恐怖,因为仅仅只需要一句代码,就可以获得你系统的剪切板内容,假如说用户在本地的words文档刚好复制了一些非常机密的内容,而接下来刚好打开了某个具有上方代码脚本的网站,那你剪切板的内容不知不觉就被截取了,你的隐私受到了直接威胁。
所以除了IE,其他浏览器基本上都是不能获取系统剪切板内容的,无论你怎么操作。
事实上其他浏览器还是同样有copy事件的。我们看一下:
$('body').on('copy', function (e) {
e.preventDefault();//阻止默认行为
if(!window.clipboardData) {
window.clipboardData = e.originalEvent.clipboardData;
}
console.log(clipboardData.getData("text/plain")); // 无论你怎么获取都是空
console.log(e);
console.log(e.originalEvent);
console.log(clipboardData);
});
我们打印一下事件 event。
可以发现,在event对象下originalEvent下有一个clipboardData对象,即剪切板对象。那尝试一下看看能不能拿到剪切板的数据。你会发现无论你copy啥,items的长度永远是0,出来的结果也永远为空。这是很好的,因为会比较安全。
那其他浏览器为了隐私安全默认不给拿剪切板的数据(当然你可以通过改变浏览器的配置),那设置剪切板的数据可以吗?因为设置,改变剪切板的数据并不会造成隐私问题。
实际上是可以的。
看一下代码:
$('body').on('copy', function (e) {
e.preventDefault();//阻止默认行为
if(!window.clipboardData) {
window.clipboardData = e.originalEvent.clipboardData;
}
clipboardData.setData('text/plain','hello, my name is dorsey');
});
此时你会发现,无论你怎么copy,是ctrl + C还是鼠标右键拷贝,最终的ctrl + V结果都是hello, my name is dorsey。
尽管我们能设置剪切板的值,然而设置的值大多都是基于用户复制的结果做一些补充,比如加一些版权信息,加一些作者自定义信息。然而浏览器的隐私安全机制导致我们无法拿剪切板的内容。那又该如何着手?
看了慕课网有这样的功能,而通常此类的方式,有一个办法是通过flash来获取。那我们关闭一下浏览器的flash。看看慕课网的这个修改剪切板的效果会不会消失。
此时,再次去慕课网拷贝,你会发现,效果还是在。那到底它是怎么拿到复制的内容的呢?
既然剪切板无法拿到数据,那何不换个角度,既然你要复制,那首先得选中要复制的内容,对吧?那是不是有什么API是可以拿到这个值的呢?
答案是肯定的。
$('body').on('copy', function (e) {
e.preventDefault();//阻止默认行为
var select = getSelection();
console.log(select.toString());
});
看一下getSelection到底返回了什么?
直接查看对象里面的什么选取开始节点什么的可能不是很直观,但这个可以直接通过toString方法直接返回那串字符串。看看MDN:
此时,当你拷贝了啥,在控制台就很自然的打印了啥。这样我们想要的结果就拿到了。
那慕课网的实现机制是否是这样的呢?我们看一看它的代码,经过查找,找到这样的片段。
这个片段是移除我们所选内容,而刚刚的toString()方法是否会被用到呢?
好像没有,有些尴尬哈,不过实现的方式还是贴出来给大家看看。
当然实际的开发可能并非通过ES5以下的开发方式,而是通过ES6+webpack+babel打包的方式来转译,但其实只要看到我们想要的内容,知道了它的实现机理,那就够了。
基于上面的思考,简单实现一个看看:
HTML部分:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>change copy content</title>
</head>
<body>
<div>你好啊</div>
1231232123198
<script src='../jquery.min.js' type='text/javascript'></script>
<script src='js/changeCopyContent.js' type='text/javascript'></script>
</body>
</html>
JavaScript部分
$(function () {
contain.initPage();
contain.initEvent();
});
(function (factory) {
factory();
})(function () {
window.contain = {
initEvent: initEvent,
initPage: initPage
}
function initPage () {
initDOMHeight();
}
function initEvent () {
$('body').on('copy', function (e) {
e.preventDefault();//阻止默认行为
var select = getSelection();
if(!window.clipboardData) {
window.clipboardData = e.originalEvent.clipboardData;
}
clipboardData.setData('text/plain', select + '\n\nhello, my name is dorsey');
// console.log(clipboardData.getData("text/plain"));
// clipboardData.setData('text/plain','hello, my name is dorsey');
// console.log(e);
// console.log(e.originalEvent);
// console.log(clipboardData);
});
}
function initDOMHeight () {
$('body').css('height', document.documentElement.clientHeight + 'px');
}
})
再看一下效果: