JS如何使用剪贴板操作Clipboard API


Posted in Javascript onMay 17, 2021

一、Document.execCommand() 方法

Document.execCommand()是操作剪贴板的传统方法,各种浏览器都支持。

它支持复制、剪切和粘贴这三个操作。

  • document.execCommand('copy')(复制)
  • document.execCommand('cut')(剪切)
  • document.execCommand('paste')(粘贴)

(1)复制操作

复制时,先选中文本,然后调用document.execCommand('copy'),选中的文本就会进入剪贴板。

const inputElement = document.querySelector('#input');
inputElement.select();
document.execCommand('copy');

上面示例中,脚本先选中输入框inputElement里面的文字(inputElement.select()),然后document.execCommand('copy')将其复制到剪贴板。

注意,复制操作最好放在事件监听函数里面,由用户触发(比如用户点击按钮)。如果脚本自主执行,某些浏览器可能会报错。

(2)粘贴操作

粘贴时,调用document.execCommand('paste'),就会将剪贴板里面的内容,输出到当前的焦点元素中。

const pasteText = document.querySelector('#output');
pasteText.focus();
document.execCommand('paste');

(3)缺点

Document.execCommand()方法虽然方便,但是有一些缺点。

首先,它只能将选中的内容复制到剪贴板,无法向剪贴板任意写入内容。

其次,它是同步操作,如果复制/粘贴大量数据,页面会出现卡顿。有些浏览器还会跳出提示框,要求用户许可,这时在用户做出选择前,页面会失去响应。

为了解决这些问题,浏览器厂商提出了异步的 Clipboard API。

二、异步 Clipboard API

Clipboard API 是下一代的剪贴板操作方法,比传统的document.execCommand()方法更强大、更合理。

它的所有操作都是异步的,返回 Promise 对象,不会造成页面卡顿。而且,它可以将任意内容(比如图片)放入剪贴板。

navigator.clipboard属性返回 Clipboard 对象,所有操作都通过这个对象进行。

const clipboardObj = navigator.clipboard;

如果navigator.clipboard属性返回undefined,就说明当前浏览器不支持这个 API。

由于用户可能把敏感数据(比如密码)放在剪贴板,允许脚本任意读取会产生安全风险,所以这个 API 的安全限制比较多。

首先,Chrome 浏览器规定,只有 HTTPS 协议的页面才能使用这个 API。不过,开发环境(localhost)允许使用非加密协议。

其次,调用时需要明确获得用户的许可。权限的具体实现使用了 Permissions API,跟剪贴板相关的有两个权限:clipboard-write(写权限)和clipboard-read(读权限)。"写权限"自动授予脚本,而"读权限"必须用户明确同意给予。也就是说,写入剪贴板,脚本可以自动完成,但是读取剪贴板时,浏览器会弹出一个对话框,询问用户是否同意读取。

JS如何使用剪贴板操作Clipboard 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 对象

Clipboard 对象提供了四个方法,用来读写剪贴板。它们都是异步方法,返回 Promise 对象。

3.1 Clipboard.readText()

Clipboard.readText()方法用于复制剪贴板里面的文本数据。

document.body.addEventListener(
  'click',
  async (e) => {
    const text = await navigator.clipboard.readText();
    console.log(text);
  }
)

上面示例中,用户点击页面后,就会输出剪贴板里面的文本。注意,浏览器这时会跳出一个对话框,询问用户是否同意脚本读取剪贴板。

如果用户不同意,脚本就会报错。这时,可以使用try...catch结构,处理报错。

async function getClipboardContents() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('Pasted content: ', text);
  } catch (err) {
    console.error('Failed to read clipboard contents: ', err);
  }
}

3.2 Clipboard.read()

Clipboard.read()方法用于复制剪贴板里面的数据,可以是文本数据,也可以是二进制数据(比如图片)。该方法需要用户明确给予许可。

该方法返回一个 Promise 对象。一旦该对象的状态变为 resolved,就可以获得一个数组,每个数组成员都是 ClipboardItem 对象的实例。

async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      for (const type of clipboardItem.types) {
        const blob = await clipboardItem.getType(type);
        console.log(URL.createObjectURL(blob));
      }
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
}

ClipboardItem 对象表示一个单独的剪贴项,每个剪贴项都拥有ClipboardItem.types属性和ClipboardItem.getType()方法。

ClipboardItem.types属性返回一个数组,里面的成员是该剪贴项可用的 MIME 类型,比如某个剪贴项可以用 HTML 格式粘贴,也可以用纯文本格式粘贴,那么它就有两个 MIME 类型(text/html和text/plain)。

ClipboardItem.getType(type)方法用于读取剪贴项的数据,返回一个 Promise 对象。该方法接受剪贴项的 MIME 类型作为参数,返回该类型的数据,该参数是必需的,否则会报错。

3.3 Clipboard.writeText()

Clipboard.writeText()方法用于将文本内容写入剪贴板。

document.body.addEventListener(
  'click',
  async (e) => {
    await navigator.clipboard.writeText('Yo')
  }
)

上面示例是用户在网页点击后,脚本向剪贴板写入文本数据。

该方法不需要用户许可,但是最好也放在try...catch里面防止报错。

async function copyPageUrl() {
  try {
    await navigator.clipboard.writeText(location.href);
    console.log('Page URL copied to clipboard');
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}

3.4 Clipboard.write()

Clipboard.write()方法用于将任意数据写入剪贴板,可以是文本数据,也可以是二进制数据。

该方法接受一个 ClipboardItem 实例作为参数,表示写入剪贴板的数据。

try {
  const imgURL = 'https://dummyimage.com/300.png';
  const data = await fetch(imgURL);
  const blob = await data.blob();
  await navigator.clipboard.write([
    new ClipboardItem({
      [blob.type]: blob
    })
  ]);
  console.log('Image copied.');
} catch (err) {
  console.error(err.name, err.message);
}

上面示例中,脚本向剪贴板写入了一张图片。注意,Chrome 浏览器目前只支持写入 PNG 格式的图片。

ClipboardItem()是浏览器原生提供的构造函数,用来生成ClipboardItem实例,它接受一个对象作为参数,该对象的键名是数据的 MIME 类型,键值就是数据本身。

下面的例子是将同一个剪贴项的多种格式的值,写入剪贴板,一种是文本数据,另一种是二进制数据,供不同的场合粘贴使用。

function copy() {
  const image = await fetch('kitten.png');
  const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
  const item = new ClipboardItem({
    'text/plain': text,
    'image/png': image
  });
  await navigator.clipboard.write([item]);
}

四、copy 事件,cut 事件

用户向剪贴板放入数据时,将触发copy事件。

下面的示例是将用户放入剪贴板的文本,转为大写。

const source = document.querySelector('.source');

source.addEventListener('copy', (event) => {
  const selection = document.getSelection();
  event.clipboardData.setData('text/plain', selection.toString().toUpperCase());
  event.preventDefault();
});

上面示例中,事件对象的clipboardData属性包含了剪贴板数据。它是一个对象,有以下属性和方法。

  • Event.clipboardData.setData(type, data):修改剪贴板数据,需要指定数据类型。
  • Event.clipboardData.getData(type):获取剪贴板数据,需要指定数据类型。
  • Event.clipboardData.clearData([type]):清除剪贴板数据,可以指定数据类型。如果不指定类型,将清除所有类型的数据。
  • Event.clipboardData.items:一个类似数组的对象,包含了所有剪贴项,不过通常只有一个剪贴项。

下面的示例是拦截用户的复制操作,将指定内容放入剪贴板。

const clipboardItems = [];

document.addEventListener('copy', async (e) => {
  e.preventDefault();
  try {
    let clipboardItems = [];
    for (const item of e.clipboardData.items) {
      if (!item.type.startsWith('image/')) {
        continue;
      }
      clipboardItems.push(
        new ClipboardItem({
          [item.type]: item,
        })
      );
      await navigator.clipboard.write(clipboardItems);
      console.log('Image copied.');
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
});

上面示例中,先使用e.preventDefault()取消了剪贴板的默认操作,然后由脚本接管复制操作。

cut事件则是在用户进行剪切操作时触发,它的处理跟copy事件完全一样,也是从Event.clipboardData属性拿到剪切的数据。

五、paste 事件

用户使用剪贴板数据,进行粘贴操作时,会触发paste事件。

下面的示例是拦截粘贴操作,由脚本将剪贴板里面的数据取出来。

document.addEventListener('paste', async (e) => {
  e.preventDefault();
  const text = await navigator.clipboard.readText();
  console.log('Pasted text: ', text);
});

以上就是JS如何使用剪贴板操作Clipboard API的详细内容,更多关于JS如何使用剪贴板操作的资料请关注三水点靠木其它相关文章!

Javascript 相关文章推荐
js几个验证函数代码
Mar 25 Javascript
javascript getElementsByTagName
Jan 31 Javascript
javascript框架设计读书笔记之字符串的扩展和修复
Dec 02 Javascript
jQuery中判断对象是否存在的方法汇总
Feb 24 Javascript
JavaScript实现多种排序算法
Feb 24 Javascript
javascript之Array 数组对象详解
Jun 07 Javascript
微信小程序 二维码canvas绘制实例详解
Jan 06 Javascript
Vue拖拽组件开发实例详解
May 11 Javascript
JS实现监控微信小程序的原理
Jun 15 Javascript
vue自定义switch开关组件,实现样式可自行更改
Nov 01 Javascript
原型和原型链 prototype和proto的区别详情
Nov 02 Javascript
JavaScript声明变量和数据类型的转换
Apr 12 Javascript
详解Node.js如何处理ES6模块
May 15 #Javascript
详解vue中v-for的key唯一性
解读Vue组件注册方式
May 15 #Vue.js
如何理解Vue简单状态管理之store模式
May 15 #Vue.js
Vue如何实现组件间通信
May 15 #Vue.js
详解Vue的sync修饰符
May 15 #Vue.js
深入理解Vue的数据响应式
May 15 #Vue.js
You might like
Javascript实现的分页函数
2007/02/07 Javascript
JS 页面自动加载函数(兼容多浏览器)
2009/05/18 Javascript
JS实现最简单的冒泡排序算法
2017/02/15 Javascript
angular中使用Socket.io实例代码
2017/06/03 Javascript
vue.js学习之vue-cli定制脚手架详解
2017/07/02 Javascript
详解angularJS自定义指令间的相互交互
2017/07/05 Javascript
Iphone手机、安卓手机浏览器控制默认缩放大小的方法总结(附代码)
2017/08/18 Javascript
打造通用的匀速运动框架(实例讲解)
2017/10/17 Javascript
本地搭建微信小程序服务器的实现方法
2017/10/27 Javascript
详解在React.js中使用PureComponent的重要性和使用方式
2018/07/10 Javascript
jQuery 实现倒计时天,时,分,秒功能
2018/07/31 jQuery
JavaScript时间与时间戳的转换操作实例分析
2018/12/07 Javascript
Vue Prop属性功能与用法实例详解
2019/02/23 Javascript
ES6知识点整理之Proxy的应用实例详解
2019/04/16 Javascript
Python open读写文件实现脚本
2008/09/06 Python
python音频处理用到的操作的示例代码
2017/10/27 Python
python中文分词,使用结巴分词对python进行分词(实例讲解)
2017/11/14 Python
python MysqlDb模块安装及其使用详解
2018/02/23 Python
python3使用pandas获取股票数据的方法
2018/12/22 Python
Python 根据日志级别打印不同颜色的日志的方法示例
2019/08/08 Python
django创建最简单HTML页面跳转方法
2019/08/16 Python
python中rc1什么意思
2020/06/19 Python
Python爬虫获取op.gg英雄联盟英雄对位胜率的源码
2021/01/29 Python
pandas按条件筛选数据的实现
2021/02/20 Python
JackJones官方旗舰店:杰克琼斯男装
2018/03/27 全球购物
node中使用shell脚本的方法步骤
2021/03/23 Javascript
大学生简历求职信
2014/06/24 职场文书
政协会议宣传标语
2014/10/09 职场文书
义诊活动通知
2015/04/24 职场文书
学术研讨会主持词
2015/07/04 职场文书
导游词之南迦巴瓦峰
2019/11/19 职场文书
element多个表单校验的实现
2021/05/27 Javascript
关于antd tree 和父子组件之间的传值问题(react 总结)
2021/06/02 Javascript
python脚本框架webpy模板控制结构
2021/11/20 Python
nginx配置之并发频次限制
2022/04/18 Servers
避坑之 JavaScript 中的toFixed()和正则表达式
2022/04/19 Javascript