Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js] 第485天 写一个方法,当复制页面中的内容时,同时把版权信息也复制上 #2771

Open
haizhilin2013 opened this issue Aug 12, 2020 · 2 comments
Labels
js JavaScript

Comments

@haizhilin2013
Copy link
Collaborator

第485天 写一个方法,当复制页面中的内容时,同时把版权信息也复制上

3+1官网

我也要出题

@haizhilin2013 haizhilin2013 added the js JavaScript label Aug 12, 2020
@longhui520
Copy link

@CoderLeiShuo
Copy link

CoderLeiShuo commented Aug 21, 2020

自己最近刚好写了一篇这样的文章:能力有限,如有错误,请大家批评指正
查看原文请点击这里:👉复制文章内容时添加版权信息

复制文章内容时添加版权信息

前言

在复制有些网站的文章时,通常会发现,复制的内容还带了一个“小尾巴”,上边附带着版权信息。

例如:

作者:CoderLeiShuo
链接:https://juejin.im/user/4160207732875736
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在本篇文章中,尝试来实现一下这种效果。

大致原理就是在用户复制时,获取用户选中的将要复制的内容,然后再加上版权信息即可。

window.getSelection()方法

如何获取用户复制的内容呢?我们可以通过window.getSelection()方法,它返回一个**Selection对象**,表示用户选择的文本范围或光标的当前位置。当然,你也可以用document.getSelection,它们二者等价。

image-20200817144520824

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

image-20200817145243401

👉查阅Selection对象具体信息请点击此处

我们最终要获取的是选中区域的纯文本,而不是一个Seletion对象。因此需要将Selection对象转换成字符串,可以通过拼接一个空字符串或使用String.toString()方法。

let selObj = window.getSelection();
let selectedTxt = selObj + '';
// 或者
let selectedTxt = selObj.toString();

我们在网页中尝试一下:

image-20200817145800258

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

image-20200817150135288

可以看到,我们已经获取到了所选择的内容。

window.getSelection()在IE8及以下的浏览器上不支持

element.oncopy事件

上一步操作中,我们已经成功获取到了选区中的文本内容。现在我们要开始实现复制时给复制的内容添加信息的效果了。

因此我们需要给element.oncopy事件绑定相应的函数,实现相应功能。

oncopy属性用来获取或设置当前元素的copy事件的事件处理函数。注意,oncopy属性是可以给其他元素进行设置的,不要因为我们一般都设置在windowdocument上,就认为它只能给它们设置。

我们先来看一个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将会显示'复制被阻止'字样!

2020-8-17-15-19-33

并且由于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>

image-20200817152955070

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

image-20200817152903237

那么,如果我们将copytext返回出去,是不是就可以实现了呢?

于是,函数中加入return copytext;语句。来看一下结果:

image-20200817153252311

很不幸,粘贴的内容中还是选中的那些文字,并不是我们需要的拼接后的字符串

原因有两点:

  1. oncopy绑定的函数中,我们返回context是没有用的,而应该返回false,代表取消复制的默认行为。否则,无论你拼接什么的内容,剪贴板里的内容仍然只有你复制的那些。
  2. 但是当你取消复制事件的默认行为后,剪贴板就无法得到复制的内容,这就需要我们手动将拼接后的字符串写入剪贴板。

clipboardData对象

取消默认的复制行为很好办,接下来,我们要详细研究一下剪贴板了。

clipboardData对象:用于访问及修改剪贴板中的数据

不同浏览器,所属的对象不同:在 IE 中这个对象是window对象的属性,在ChromeSafariFirefox中,这个对象是相应的event对象的属性。所以我们在使用的时候,需要做一下如下兼容

document.oncopy = e => {
    let clipboardData = e.clipboardData || window.clipboardData;
    // 获取clipboardData对象 + do something
}

对象方法

该对象有三个方法:getData()setData()clearData()

getData()方法

getData()方法接受一个format参数,即要取得的数据的格式。数据类型有:text/plaintext/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>

来看一下效果:

2020-8-17-15-19-34

后续

至此,我们已经实现了基本的功能,但是目前的代码还没有兼容低版本的IE浏览器,并且还没有实现带格式复制的功能。后续将继续进行完善。

参考文章

本篇文章在写作过程中,参考了以下文章的内容。

JavaScript中的复制粘贴功能

MDN element.oncopy

复制网页内容自动添加版权信息的方法(兼容IE所有版本)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
js JavaScript
Projects
None yet
Development

No branches or pull requests

3 participants