注册 登录

清河洛

js中的剪贴板操作

qingheluo2019-03-07清河洛464
目前,一共有三种方法可以实现剪贴板操作Document.execCommand()方法 异步Clipboard API copy事件和paste事件 Document.execCommand()方法是操作剪贴板的传统方法,各种浏览器都支持,该方法只能操作可编辑元素,如input、textarea标签或设置了contenteditable属性为true的元素一般的操作步骤:1、通过getElementById()等或querySelector[All]()方法选定元素 2、通过element.focus()方法聚焦到元素,粘贴等操作需要 3、通过element.select()方法选中文本...

目前,一共有三种方法可以实现剪贴板操作

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);
});


网址导航