js中的剪贴板操作
目前,一共有三种方法可以实现剪贴板操作
Document.execCommand()方法
异步Clipboard API
copy事件和paste事件
Document.execCommand()方法
是操作剪贴板的传统方法,各种浏览器都支持,该方法只能操作可编辑元素,如input、textarea标签或设置了contenteditable属性为true的元素
一般的操作步骤:
1、通过getElementById()等或querySelector[All]()方法选定元素
2、通过element.focus()方法聚焦到元素,粘贴等操作需要
3、通过element.select()方法选中文本,复制、剪切、删除等操作需要
4、运行指定的命令
document.execCommand(command):执行一个指定的命令
方法返回一个bool值
command是一个字符串,表示具体的操作
可选的command有:
copy:复制
cut:剪切
delete:删除
paste:粘贴
selectAll:全选编辑区中的内容,效果和select()相同
forwardDelete:删除光标所在位置的字符,相当于按一下删除键
undo:撤销最近执行的命令
redo:重做被撤销的操作
复制操作最好放在事件监听函数里面,由用户触发(如点击按钮),如果脚本自主执行,某些浏览器可能会报错
当前端开发中需要使用js复制文字时,如果需要复制的文字不是input或者textarea标签内容,我们可以在html文件中
1、创建一个input或者textarea并隐藏,<strong>不能使用display:none或者宽高为0隐藏</strong>(亲测chrome上不行):
input{position:absolute/fixed;top:0;left:0;opacity: 0;z-index:-10;}
2、input.value=p.innerHTML,
3、input.select()选中input的内容
4、document.execCommand('copy')复制文本
缺点
1、只能将选中的内容复制到剪贴板,无法向剪贴板写入自定义内容
2、该方法是同步操作,如果复制/粘贴大量数据,页面会出现卡顿
3、有些浏览器会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应
为了解决这些问题,浏览器厂商提出了异步的Clipboard API
异步Clipboard API
所有操作都是异步的,返回Promise对象,不会造成页面卡顿。而且可以向剪贴板写入自定义内容甚至二进制图片
通过navigator.clipboard属性获取Clipboard对象,后续所有操作都通过这个对象进行
如果navigator.clipboard属性返回undefined,说明当前浏览器不支持该API
由于允许脚本任意读取剪贴板会产生安全风险,所以这个API的安全限制比较多
Chrome浏览器规定,只有HTTPS协议的页面才能使用这个API。不过,开发环境(localhost)允许使用非加密协议
跟剪贴板相关的有两个权限:clipboard-write(写权限)和clipboard-read(读权限),其中“写权限”自动授予脚本,而“读权限”必须用户明确同意给予,权限的具体实现使用了Permissions API
脚本读取的总是当前页面的剪贴板,如果把相关的代码粘贴到开发者工具中直接运行,可能会报错,因为此时的当前页面是开发者工具的窗口,而不是网页页面
(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
})();
以上代码粘贴到开发者工具里面运行会报错
代码运行时开发者工具窗口是当前页,这个页面不存在Clipboard API依赖的DOM接口
一个解决方法就是,相关代码放到setTimeout()里面延迟运行,在调用函数之前快速点击浏览器的页面窗口,将其变成当前页
setTimeout(async () => {
const text = await navigator.clipboard.readText();
console.log(text);
}, 2000);
以上代码粘贴到开发者工具运行后,快速点击一下网页的页面窗口,使其变为当前页,就不会报错了
Clipboard对象提供了四个方法,用来读写剪贴板。它们都是异步方法,返回Promise对象
readText():读取剪贴板里面的文本数据
一旦该对象的状态变为 resolved,会获得一个字符串
read():读取剪贴板里面的数据,可以是文本数据,也可以是二进制数据
一旦该对象的状态变为 resolved,会获得一个数组,每个数组成员都是ClipboardItem对象的实例
ClipboardItem对象表示一个单独的剪贴项,每个剪贴项都拥有ClipboardItem.types属性和ClipboardItem.getType()方法
ClipboardItem.types属性返回一个数组,里面的成员是该剪贴项可用的MIME类型
ClipboardItem.getType(type)方法用于读取剪贴项的数据,返回一个Promise对象
接受剪贴项的MIME类型作为参数,返回该类型的数据
type参数是必需的,否则会报错
writeText(str):将字符串内容写入剪贴板
write(data_array):将数据内容写入到剪贴板,传入一个数组,每个元素为一个ClipboardItem对象
ClipboardItem(obj)是浏览器原生提供的构造函数,用来生成ClipboardItem实例
它接受一个对象作为参数,该对象的键名是数据的MIME类型,键值就是数据本身
function copy() {
const image = await fetch('demo.png');
const text = new Blob(['dem.png图片'], {type: 'text/plain'});
const item = new ClipboardItem({
'text/plain': text,
'image/png': image
});
await navigator.clipboard.write([item]);
}
copy和cut事件
当用户复制时触发copy事件、用户剪切时触发cut事件,这两个事件的本质相似,都是向剪贴板中写入内容,返回的事件对象也是相同的
可以使用event.preventDefault()取消默认行为
Event.clipboardData.setData(type, data):修改剪贴板数据,需要指定数据类型
Event.clipboardData.getData(type):获取剪贴板数据,需要指定数据类型
Event.clipboardData.clearData([type]):清除剪贴板数据,可以指定数据类型。如果不指定类型,将清除所有类型的数据
Event.clipboardData.items:一个类似数组的对象,包含了所有剪贴项,不过通常只有一个剪贴项
document.querySelector("div.demo").addEventListener('copy',(event)=>{
const selection = document.getSelection();
# 获取表示用户选择的文本范围或光标的当前位置的Selection对象
event.clipboardData.setData("text/plain", selection.toString().toUpperCase());
# selection.toString()表示获取选中区域的文本内容
# 修改复制的内容
selection.deleteFromDocument();
# 删除选中文本
removeAllRanges()
# 取消选中文本的选中状态
event.preventDefault();
# 取消默认行为
})
document.querySelector("div.demo").oncopy = (event)=>{ ... }
以上代码会将目标区域中的复制动作修改为剪贴动作,并将复制的内容转化为大写
paste事件
当用户粘贴时触发paste事件,如果脚本要操作粘贴事件需要有剪贴板的读取权限
通过navigator.clipboard.readText()或navigator.clipboard.read()读取内容
也可以通过Event.clipboardData.getData(type)来获取内容
document.addEventListener('paste', async (e) => {
e.preventDefault();
const text = await navigator.clipboard.readText();
console.log('要粘贴的内容为: ', text);
});