目录
一、简介
浏览器允许 JavaScript 脚本读写剪贴板,自动复制或粘贴内容。
一般来说,脚本不应该改动用户的剪贴板,以免不符合用户的预期。但是,有些时候这样做确实能够带来方便,比如“一键复制”功能,用户点击一下按钮,指定的内容就自动进入剪贴板。
目前,一共有三种方法可以实现剪贴板操作。
Document.execCommand()
方法。- 异步的
Clipboard API
。 copy
事件和paste
事件。
二、Document.execCommand()
方法(弃用)
已弃用: 不再推荐使用该特性。虽然一些浏览器仍然支持它,但也许已从相关的 web 标准中移除,也许正准备移除或出于兼容性而保留。请尽量不要使用该特性,并更新现有的代码;参见本页面底部的兼容性表格以指导你作出决定。请注意,该特性随时可能无法正常工作。
1、语法
bool = document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)
该方法有三个参数:
- 第一个参数:字符串类型,传入需要操作的命令。如:‘cut’,‘copy’,'paste’等等。
- 第二个参数:布尔类型,是否展示用户界面,一般为 false。
- 第三个参数:一些命令(例如 insertImage)需要额外的参数(insertImage 需要提供插入 image 的 url),默认为 null。
返回值是布尔类型,如果是 false 则表示操作不被支持或未被启用。
如:
2、复制操作
复制时,先选中文本,然后调用document.execCommand('copy')
,选中的文本就会进入剪贴板。
const inputElement = document.querySelector('#input');
inputElement.select();
document.execCommand('copy');
注意,复制操作最好放在事件监听函数里面,由用户触发(比如用户点击按钮)。如果脚本自主执行,某些浏览器可能会报错。
3、粘贴操作
粘贴时,调用document.execCommand('paste')
,就会将剪贴板里面的内容,输出到当前的焦点元素中。
const pasteText = document.querySelector('#output');
pasteText.focus();
document.execCommand('paste');
4、小结
Document.execCommand()
方法虽然方便,但是有一些缺点。
首先,它只能将选中的内容复制到剪贴板,无法向剪贴板任意写入内容。
其次,它是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。
为了解决这些问题,浏览器厂商提出了异步的 Clipboard API
。
三、 异步 Clipboard API
剪贴板 Clipboard API 提供了响应剪贴板命令(剪切、复制和粘贴)与异步读写系统剪贴板的能力。从权限 Permissions API 获取权限之后,才能访问剪贴板内容;如果用户没有授予权限,则不允许读取或更改剪贴板内容。
只有在用户事先授予网站或应用对剪切板的访问许可之后,才能使用异步剪切板读写方法。许可操作必须通过取得权限 Permissions API 的 “clipboard-read” 和/或 “clipboard-write” 项获得
它的所有操作都是异步的,返回 Promise 对象,不会造成页面卡顿。而且,它可以将任意内容(比如图片)放入剪贴板。
系统剪贴板暴露于全局属性 Navigator.clipboard
之中。
theClipboard = navigator.clipboard;
返回一个用于访问系统剪切板的 Clipboard 对象。
用法:
navigator.clipboard.readText().then(
clipText => document.querySelector(".cliptext").innerText = clipText);;
这个代码片段将 HTML 中拥有类名 “cliptext” 的第一个元素的内容替换为剪切板中的内容。这段代码可用于在浏览器拓展中定时自动更新或者由事件触发,实时显示当前剪切板上的内容。
如果剪切板为空,或者不包含文本,则 “cliptext” 元素的内容将被清空。这是因为在剪切板为空或者不包含文本时,readText() 会返回一个空字符串。
四、Clipboard对象
Clipboard 对象提供了四个方法,用来读写剪贴板。它们都是异步方法,返回 Promise 对象。
分别是:
- Clipboard.read()
- Clipboard.readText()
- Clipboard.write()
- Clipboard.writeText()
1、Clipboard.read()
Clipboard.read()
方法用于复制剪贴板里面的数据,可以是文本数据,也可以是二进制数据(比如图片)。该方法需要用户明确给予授权许可。
返回的一个Promise对象,一旦该对象的状态变为 resolved,就可以获得一个数组,每个数组成员都是 ClipboardItem 对象的实例。
例如:
navigator.permissions.query({name: "clipboard-read"}).then(result => {
// 先查询用户授权是否已经允许
if (result.state == "granted" || result.state == "prompt") {
navigator.clipboard.read().then(data => {
for (let i=0; i<data.items.length; i++) {
if (data.items[i].type != "text/plain") {
alert("剪切板内容不是一个文本");
} else {
textElem.innerText = data.items[i].getAs("text/plain");
}
}
});
}
});
2、Clipboard.readText()
Clipboard.readText()
方法用于复制剪贴板里面的文本数据。
要从剪贴板中读取非文本内容,请改用read()
方法。您可以使用 writeText()
将文本写入剪贴板。
例如:
navigator.clipboard.readText().then(
clipText => document.getElementById("outbox").innerText = clipText);
这些需要用户操作才能触发。比如点击等等。
3、Clipboard.write()
Clipboard 的方法 write()
写入图片等任意的数据到剪贴板。这个方法可以用于实现剪切和复制的功能。
但是你要提前获取 “Permissions API” 的 “clipboard-write” 权限才能将数据写入到剪贴板。
语法:
var promise = navigator.clipboard.write(dataTransfer)
例如:
function setClipboard(text) {
let data = new DataTransfer();
data.items.add("text/plain", text);
navigator.clipboard.write(data).then(function() {
/* success */
}, function() {
/* failure */
});
}
代码创建了一个 DataTransfer
对象,要替换的内容存储在这里。执行 DataTransferItemList.add()
将数据写入进去,然后执行 write()
方法,指定执行成功或错误的结果。
4、Clipboard.writeText()
Clipboard 接口的 writeText()
方法可以写入特定字符串到操作系统的剪切板。
语法:
var promise = navigator.clipboard.writeText(newClipText)
返回一个Promise ,一旦剪贴板的内容被更新,它就会被解析。如果调用者没有写入剪贴板的权限,则拒绝写入剪切板(reject)。
例如:
navigator.clipboard.writeText("<empty clipboard>").then(function() {
/* clipboard successfully set */
}, function() {
/* clipboard write failed */
});
五、cut事件,copy事件和paste事件
cut事件
进行剪切操作触发事件
例子:
html
<div class="source" contenteditable="true">Cut text from this box.</div>
<div class="target" contenteditable="true">And paste it into this one.</div>
JavaScript
const source = document.querySelector("div.source");
source.addEventListener("cut", (event) => {
const selection = document.getSelection();
event.clipboardData.setData("text/plain", selection.toString().toUpperCase());
selection.deleteFromDocument();
event.preventDefault();
});
cut事件则是在用户进行剪切操作时触发。从event.clipboardData中拿到数据。
copy事件
用户向剪贴板放入数据时,将触发copy事件。
html
<div class="source" contenteditable="true">Copy text from this box.</div>
<div class="target" contenteditable="true">And paste it into this one.</div>
JavaScript
const source = document.querySelector("div.source");
source.addEventListener("copy", (event) => {
const selection = document.getSelection();
event.clipboardData.setData("text/plain", selection.toString().toUpperCase());
event.preventDefault();
});
paste事件
用户使用剪贴板数据,进行粘贴操作时,会触发paste事件。
<div class="source" contenteditable="true">Copy text from this box.</div>
<div class="target" contenteditable="true">And paste it into this one.</div>
JavaScript
const target = document.querySelector("div.target");
target.addEventListener("paste", (event) => {
event.preventDefault();
let paste = (event.clipboardData || window.clipboardData).getData("text");
paste = paste.toUpperCase();
const selection = window.getSelection();
if (!selection.rangeCount) return;
selection.deleteFromDocument();
selection.getRangeAt(0).insertNode(document.createTextNode(paste));
selection.collapseToEnd();
});