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 相关文章推荐
Ucren Virtual Desktop V2.0
Nov 07 Javascript
js限制文本框输入长度两种限制方式(长度、字节数)
Dec 19 Javascript
JS保存、读取、换行、转Json报错处理方法
Jun 14 Javascript
js螺旋动画效果的具体实例
Nov 15 Javascript
JavaScript中实现map功能代码分享
Jun 11 Javascript
three.js加载obj模型的实例代码
Nov 10 Javascript
chorme 浏览器记住密码后input黄色背景处理方法(两种)
Nov 22 Javascript
使用Vue完成一个简单的todolist的方法
Dec 01 Javascript
layui table 列宽百分比显示的实现方法
Sep 28 Javascript
JS实现时间校验的代码
May 25 Javascript
基于js实现的图片拖拽排序源码实例
Nov 04 Javascript
JavaScript中的Proxy对象
Nov 27 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
php在线打包程序源码
2008/07/27 PHP
用PHP实现读取和编写XML DOM代码
2010/04/07 PHP
header中Content-Disposition的作用与使用方法
2012/06/13 PHP
PHP Warning: Module 'modulename' already loaded in问题解决办法
2015/03/16 PHP
php实现中文字符截取防乱码方法汇总
2015/04/29 PHP
php实现学生管理系统
2020/03/21 PHP
利用PHP如何写APP接口详解
2016/08/23 PHP
php实现基于PDO的预处理示例
2017/03/28 PHP
thinkPHP框架实现生成条形码的方法示例
2018/06/06 PHP
Laravel框架生命周期与原理分析
2018/06/12 PHP
在jQuery1.5中使用deferred对象 着放大镜看Promise
2011/03/12 Javascript
jQuery实现当按下回车键时绑定点击事件
2014/01/28 Javascript
javascript闭包传参和事件的循环绑定示例探讨
2014/04/17 Javascript
jQuery获取上传文件的名称的正则表达式
2015/05/21 Javascript
使用three.js 画渐变的直线
2016/06/05 Javascript
jQuery实现Select左右复制移动内容
2016/08/05 Javascript
fullpage.js全屏滚动插件使用实例
2016/09/06 Javascript
AngularJS 实现JavaScript 动画效果详解
2016/09/08 Javascript
JavaScript错误处理和堆栈追踪详解
2017/04/18 Javascript
jquery实现图片跟随鼠标的实例
2017/10/17 jQuery
Vue2.5学习笔记之如何在项目中使用和配置Vue
2018/09/26 Javascript
单页面vue引入百度统计的使用方法示例详解
2018/10/13 Javascript
使用NestJS开发Node.js应用的方法
2018/12/03 Javascript
详解iframe跨域的几种常用方法(小结)
2019/04/29 Javascript
javascript的this关键字详解
2019/05/20 Javascript
Python2.7基于笛卡尔积算法实现N个数组的排列组合运算示例
2017/11/23 Python
python http基本验证方法
2018/12/26 Python
python3.6+django2.0+mysql搭建网站过程详解
2019/07/24 Python
python3中pip3安装出错,找不到SSL的解决方式
2019/12/12 Python
关于PyCharm安装后修改路径名称使其可重新打开的问题
2020/10/20 Python
python 利用Pyinstaller打包Web项目
2020/10/23 Python
上级检查欢迎词
2014/01/18 职场文书
我的五年职业生涯规划
2014/01/23 职场文书
周年庆典邀请函范文
2014/01/23 职场文书
学校花圃的标语
2014/06/18 职场文书
临时租车协议范本
2014/09/23 职场文书