异步clipboard api

Posted 玛德致

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了异步clipboard api相关的知识,希望对你有一定的参考价值。

原文地址:https://webkit.org/blog/10855/async-clipboard-api/;
第一次翻译,自觉语句什么的也有些生硬,可能存在不少问题,请大家不吝赐教,谢谢。

1.基础功能

Safari13.1 增加对async Clipboard API的支持。该api允许web开发者在剪贴板中读写文字/图片数据,并且在剪贴板数据的读写中有很多优于当前的做法。

该api主要介绍了两个功能:

  • clipboard:通过navigator.clipboard使用,包含了一些从系统剪贴板读写数据的方法;
  • clipboardItem:代表了剪贴板众多信息中的一项,目前webkit读写支持四种MIME类型:text/plain,text/html,text/uri-list和image/png;

    从概念上来说,clipboard由一个或多个clipboardItem有序组成。每个clipboardItem可能会包含多种MIME类型,比如说复制多个image文件,一般会创建多个“image/png”类型的clipboardItem,但是如果图文混合类型,一般会创建一个带有“image/png”和“text/plain”两种类型的clipboardItem。

    可以使用clipboard.read去读取系统剪切板中的数据,这个方法可以异步的获取到clipboardItem的数组集合,数组中的每一项都包含了MIME类型到blob的映射。同样的,clipboard.write可以将给定的clipboardItem数组写入系统剪切板。但如果内容只是文本的话,使用clipboard.readText和clipboard.writeText更简单方便些。

    每个clipboardItem还有presentationStyle属性,该属性表明该项最好是内联数据还是“附件”(类似file的实体),可以用于区分文本还是HTML文件。

2.代码示例

写入文本数据:

<button id="new-copy">Copy text</button>

<script>

  document.getElementById("new-copy").addEventListener("click", event => {

    navigator.clipboard.writeText("This text was copied programmatically.");

  });

</script>

这比现在需要选中text内容然后再调用execute复制文本要简单很多。


写入clipboardItem:

参数是一个clipboardItem数组,每一项MIME类型都是promise,resolve的内容可以被转为相同类型的string或者blob

<button id="copy-html">Copy text and markup</button>

<div>Then paste in the box below:</div>

<div contenteditable spellcheck="false" style="width: 200px; height: 100px; overflow: hidden; border: 1px solid black;"></div>

<script>

  document.getElementById("copy-html").addEventListener("click", event => {

    navigator.clipboard.write([

        new ClipboardItem({

            "text/plain": Promise.resolve("This text was copied using `Clipboard.prototype.write`."),

            "text/html": Promise.resolve("<p style=\'color: red; font-style: oblique;\'>This text was copied using <code>Clipboard.prototype.write</code>.</p>"),

        }),

    ]);

  });

</script>

使用dataTransfer api来复制内容的时候,需要创建一个隐藏的文本域,在文本域上注册一个copy的事件,聚焦之后通过触发程序的复制在dataTransfer里设置数据,最后调用preventDefault方法。

write和writeItem都是异步的,如果在pending的时候重新写入,前一个会立即返回reject,然后写入新的内容。

ios和macOS系统上,写入的顺序也很重要。webkit按照指定的顺序写入,先写入的有“更高的保真度”,在IOS和macOS上的原生app可以以此为根据来选择适当的UTI(universal type identifier)来读取。

读取数据:

<span style="font-weight: bold; background-color: black; color: white;">Select this text and copy</span>

<div><button id="read-html">Paste HTML below</button></div>

<div id="html-output"></div>

<script>

document.getElementById("read-html").addEventListener("click", async clickEvent => {

    let items = await navigator.clipboard.read();

    for (let item of items) {

        if (!item.types.includes("text/html"))

            continue;

        let reader = new FileReader;

        reader.addEventListener("load", loadEvent => {

            document.getElementById("html-output").innerHTML = reader.result;

        });

        reader.readAsText(await item.getType("text/html"));

        break;

    }

});

</script>

有几个点可以注意一下:

  • 和write一样,read也是异步的,获取clipboardItem和转换blob都返回的是promise
  • 读取数据时,类型会保留,写入的顺序和读取的时候是一样的

3.安全和隐私

clipboard api功能强大,可以从剪切板读取数据,所以读取时有很多安全策略,敏感数据,比如密码之类的,如果没有用户    明确的同意,是不被允许使用的。比如说复制了恶意的“text/html”信息,粘贴到另外的网页中,很有可能导致跨站脚本攻击。

以下是一些安全限制:

  • http的网站是无法使用该api的
  • 复制的请求必须在用户手势下触发,如果不是“click”,“touch”之类的用户手势,promise会返回reject
  • “text/html”和“image/png”在写入之前会脱敏,标记在js被禁用的独立文档中加载,而且只取页面的可见部分,比如script元素,注释内容,display:none以及事件属性等都会被去除。对png图片来说,被初次解码后展示图像,在被写入粘贴板之前会被再次编码,这得确保网站图片不被损坏,如果图片无法被解码,写入的promise会返回reject。更多的脱敏信息可以在Clipboard API Improvements中找到。
  • 由于用户可能并没有意识到复制了敏感信息,所以读取粘贴内容的限制比写入的限制严格很多。如果页面企图在用户手势之外用编程方式读取粘贴板的内容,会立即返回reject。但是如果用户明确的触发了粘贴操作(比如macOS的command+v快捷键或者IOS的粘贴操作),WebKit会允许程序执行粘贴操作。如果是同源访问,剪切板会自动授权。如果上述条件都不符合,WebKit就会在用户继续粘贴操作的时候展示明确的ui面板让其操作。在IOS上,它的形式是有单一选项的标注栏,在macOS上,是菜单选项。轻触或点击页面的任意一处(或者执行其他操作,比如切换tab或者隐藏safari)都会导致promise被reject。只有用户在ui上明确触发了粘贴操作,页面才会授权允许操作执行。
  • 从剪贴板读取数据也要进行脱敏,避免用户在无意中暴露敏感数据,比如image数据会被剥离EXIF数据,其中包含了名字之类的信息。读取的标记信息也会被去掉注释之类的信息。

这些政策确保了异步clipboard api开发者没有滥用以及破坏用户安全与隐私的风险,还能获得良好的开发体验。

4.未来的发展

    我们会继续完善这个api,我们会增加自定义类型的支持,也会支持更多的MIME类型,比如“image/jpeg”或者“image/svg+xml”,如果有bug欢迎提供至bugs.webkit.org

以上是关于异步clipboard api的主要内容,如果未能解决你的问题,请参考以下文章

Web API 学习笔记 - 剪切板 Clipboard API

React复制到剪贴板插件copy-to-clipboard

VB如何利用剪贴板复制、粘贴文件,用到啥API

在Nuxt.js组件中获取异步数据

Clipboard 剪贴板学习笔记

Clipboard 剪贴板学习笔记