很多网站、博客,论坛都会需要复制的功能,js如何实现复制功能呢?

比如我的博客,我的博客当时在编写的时候遇到了一个问题,就是代码块复制的问题

起初我用的是 Clipboard.js 实现代码块复制,当时也不是太了解

而且如果我有多个代码块的话,它不会随着我点击的代码块复制,而是只会复制整个页面出现的第一个代码块

最后我判断当鼠标移动到当前代码块上时,给代码块添加一个Clipboard属性(这个是可自定义的),然后使用document.querySelector获取元素进行复制(得到元素后将元素给Clipboard.js进行复制即可)随后当鼠标移出时,移除Clipboard属性(具体代码如下)

当时用的是Jquery写的,原生JS的话可以用onmouseenter(移入)和onmouseleave(移出)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

// 当鼠标移动到代码块上时执行
$(".highlight-wrap").hover(
function() {
// 移除其他代码块的 Clipboard 属性
$("[Clipboard]").removeAttr("Clipboard");
// 在当前鼠标所在的元素下的 .code 元素上添加 Clipboard属性
$(this).find(".code").attr("Clipboard", "");
}
);

// 代码块复制
var clipboard = new ClipboardJS('.clipboard', {
target: function() {
// 返回 Clipboard 属性下的内容
return document.querySelector("[Clipboard]");
}
});

// 复制成功
clipboard.on('success', function(event) {
event.trigger.innerHTML = "<i class='fa fa-check' style='color:green'></i>";
setTimeout(function () {
event.trigger.innerHTML = "<i class='fa fa-clipboard'></i>"
}, 2000)
event.clearSelection();
});
// 复制失败
clipboard.on('error', function(event) {
event.trigger.innerHTML = "<i class='fa fa-times' style='color:red'></i>";
setTimeout(function () {
event.trigger.innerHTML = "<i class='fa fa-clipboard'></i>"
}, 2000)
});

后来我决定对我的博客主题下手,整个框架大换血,移除掉Jquery,全部改用原生JS处理

原生JS实现复制文本内容的主要代码

1
2
3
4
5
6
7
// 原生js实现复制内容到剪切板

const selection = window.getSelection()// 创建Selection 对象(getSelection()方法表示用户选择的文本范围或光标的当前位置)
selection.selectAllChildren(document.querySelector(".code"))// 选中class="code"元素下的所有内容
document.execCommand("Copy");// 执行复制操作(上一行已经选中了内容)
selection.removeAllRanges()// 复制成功后,消除选中状态

复制代码块的完整代码,足足比Clipboard.js代码量少了一大截,而且不需要引入外部js

Clipboard.js库大小:
未压缩:25.5kb
已压缩:8.82kb
gzip:3kb (官方描述的3kb,我未验证过)

自己用原生JS写的关键代码才4行,如果写完整代码且复杂的高的也不会超过20行
下面是我博客代码块复制功能的完整代码

问:为什么不用onmouseenter进行鼠标移入添加属性了?
答: 不想频繁添加删除属性操作就用循环了,至于这两个哪个更快我没研究过,
使用onmouseenter还是for循环的话,因人而异吧,想用哪种方式就用哪种方式,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 执行方法
CodeCopy()
function CodeCopy(){
// 获取所有的代码块,循环获取
document.querySelectorAll(".highlight-wrap").forEach(function (item) {
item.firstChild.onclick = function () {// 点击当前代码块的第一个子元素
const selection = window.getSelection()// 创建Selection 对象(getSelection()方法表示用户选择的文本范围或光标的当前位置)
selection.selectAllChildren(item.querySelector(".code"))// 选中class="code"元素下的所有内容
document.execCommand("Copy");// 执行复制操作(上一行已经选中了内容)
selection.removeAllRanges()// 复制成功后,消除选中状态

// 复制成功,修改复制按钮icon为:✔ 颜色:绿色
item.firstChild.innerHTML = "<i class='fa fa-check' style='color:green'></i>";
setTimeout(function () { // 两秒后恢复复制按钮原icon图标
item.firstChild.innerHTML = "<i class='fa fa-clipboard'></i>"
}, 2000)
}
})
}

代码块html结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<div class="highlight-wrap" data-rel="Js">
<span class="clipboard"><!-- js代码里的 item.firstChild.onclick = 指的就是点击该按钮-->
<i class="fa fa-clipboard"></i>
</span>
<figure class="iseeu highlight js">
<table>
<tr>
<td class="gutter"><!-- 代码块行号 -->
<pre>
<span class="line">1</span>
<br>
<span class="line">2</span>
<br>
<span class="line">3</span>
<br>
.... <!-- 省略行号 -->
</pre>
</td>
<td class="code"><!-- 复制下方内容 -->
<pre>
<span class="line"></span>
<br>
<span class="line">CodeCopy()</span>
<br>
<span class="line">
<span class="function">
<span class="keyword">function</span>
<span class="title">CodeCopy</span>
(<span class="params"></span>
)
</span>
&#123;
</span>
<!-- 省略其他内容 -->
</pre>
</td>
</tr>
</table>
</figure>
</div>