最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Async Clipboard API来了

    正文概述 掘金(为之漫笔)   2020-12-21   500

    如果我问:你知道 “剪贴板”(clipboard)吗?

    恐怕没人不知道。我们每天都不知道自己要在电脑或手机上 “复制”、“粘贴” 多少回。每次 “复制”、“粘贴” 的背后,都会用到“剪贴板”。

    根据 “维基百科”:

    The clipboard is a data buffer used for short-term data storage and/or data transfer between documents or applications used by cut, copy and paste operations and provided by the operating system.

    翻译一下:

    剪贴板是一种数据缓存,用于文档或应用间短期数据的存储 / 转移,在用户执行剪切、复制和粘贴操作时会用到,由操作系统提供。

    这里最重要的一点在于,“剪贴板”是 “由操作系统提供” 的,因此它是系统级的一个软件特性。

    对于前端开发者来说,如果我问:你知道怎么操作 “剪贴板” 吗?

    很多人的第一反应可能是:使用 clipboard.js 吧……

    clipboard.js 的原理

    clipboard.js(clipboardjs.com/)是在 Github 上有 24000 多个星,其流行程度可见一斑。关于这个库的用法,大家可以自己去看,我们这里主要分析其实现原理,以便了解目前操作剪贴板的主流技术。

    简单来说,clipboard.js 利用了两个已有的 Web API(前者属于 HTML5,后者属于 HTML Editing API):

    • HTMLInputElement.select()
    • document.execCommand()

    相应地,原理也只有两步。

    第一步,创建临时的 texterea 元素、通过 CSS 隐藏起来,然后把要复制的文本赋值给这个文本区,再选择这个文本区中的所有内容:

    // https://github.com/zenorocha/clipboard.js/blob/master/src/clipboard-action.js
    /**
     * Creates a fake textarea element, sets its value from `text` property,
     * and makes a selection on it.
     */
    // selectFake()
    // 创建临时的texterea元素
    this.fakeElem = document.createElement('textarea');
    // 隐藏这个元素
    this.fakeElem.style.position = 'absolute';
    this.fakeElem.style[ isRTL ? 'right' : 'left' ] = '-9999px';
    // 把要复制的文本赋给文本区并选择全部内容
    this.fakeElem.value = this.text;
    this.selectedText = select(this.fakeElem);
    // 触发复制
    this.copyText();
    

    第二步,通过脚本触发 copy 操作,如果成功则文本会写入剪贴板,然后根据执行结果派发自定义事件:

    // https://github.com/zenorocha/clipboard.js/blob/master/src/clipboard-action.js
    /**
     * Executes the copy operation based on the current selection.
     */
    // copyText()
    succeeded = document.execCommand(this.action);
    this.handleResult(succeeded);
    
    /**
      * Fires an event based on the copy operation result.
      * @param {Boolean} succeeded
      */
    handleResult(succeeded) {
        this.emitter.emit(succeeded ? 'success' : 'error', {
            action: this.action,
            text: this.selectedText,
            trigger: this.trigger,
            clearSelection: this.clearSelection.bind(this)
        });
    }
    

    如前所述,剪贴板是由操作系统提供的,是系统级的。浏览器厂商为安全和用户体验考虑,只信任用户通过应用、文档或脚本触发的复制操作。而且,复制到剪贴板的内容来源还必须是已有的 DOM 元素。

    以上复制操作的结果是将文本内容写入剪贴板。如果要读取剪贴板中的内容,必须给粘贴(paste)事件操作注册处理程序,通过 e.clipboardData.getData() 方法获取剪贴板中的内容。这样可以在用户把内容粘贴到目标输入框之前,对剪贴板上的内容进行一些预处理。但这不是本文的重点。

    虽然 clipboard.js 使用的这种技术几乎所有浏览器都支持,但也存在诸多缺陷。

    已有技术的缺陷

    以前的技术存在什么失陷呢?除了前面需要通过编程方式通过 execCommand 模拟用户触发剪贴板的复制操作之外,还有:

    • execCommand 的初衷是编辑 DOM,而且浏览器间实现存在不少差异
    • 复制粘贴操作是同步的,会阻塞主线程,导致页面无法响应
    • 如果进而再弹窗申请授权,则可能会惹恼用户
    • 相应地,妨碍对某些类型的数据(如图片)进行无害化处理或转码操作
    • 而为避免外部利用,有时候转码又是必需的

    为了克服这些问题,W3C 开始着手制定相关标准:Clipboard API and events(www.w3.org/TR/clipboar…)。

    Clipboard API and events 定义了 Async Clipboard API,相应地增加了 clipboardchange 事件。

    Async Clipboard API

    换句话说,为避免阻塞主线程,这个新标准引入了基于 Promise 的异步剪贴板 API。由于剪贴板是系统级软件特性,所以相应的 API 挂载到了 navigator 上面:

    navigator.clipboard
    

    这个 clipboard 对象有 4 个方法:

    Promise<DataTransfer> read();
    Promise<DOMString> readText();
    Promise<void> write(DataTransfer data);
    Promise<void> writeText(DOMString data);
    

    两个读剪贴板,两个写剪贴板。

    支持读写以下数据类型:

    • text/plain
    • text/uri-list
    • text/csv
    • text/css
    • text/html
    • application/xhtml+xml
    • image/png
    • image/jpg, image/jpeg
    • image/gif
    • image/svg+xml
    • application/xml, text/xml
    • application/javascript
    • application/json
    • application/octet-stream

    read()

    navigator.clipboard.read().then(function(data) {
      for (var i = 0; i < data.items.length; i++) {
        if (data.items[i].type == "text/plain") {
          console.log("Your string: ", data.items[i].getAs("text/plain"));
        } else {
          console.error("No text/plain data on clipboard.");
        }
      }
    });
    

    readText()

    navigator.clipboard.readText().then(function(data) {
      console.log("Your string: ", data);
    });
    

    write(data)

    var data = new DataTransfer();
    data.items.add("text/plain", "Howdy, partner!");
    navigator.clipboard.write(data).then(function() {
      console.log("Copied to clipboard successfully!");
    }, function() {
      console.error("Unable to write to clipboard. :-(");
    });
    

    writeText(data)

    navigator.clipboard.writeText("Howdy, partner!").then(function() {
      console.log("Copied to clipboard successfully!");
    }, function() {
      console.error("Unable to write to clipboard. :-(");
    });
    

    注意事项

    1. navigator.clipboard 只能在 “安全上下文” 中使用。什么是“安全上下文”?简单说,就是 locahost 和 HTTPS 环境下。(可以通过 window.isSecureContext 属性取得。)
    2. 桌面浏览器中目前只有 Chrome、Firefox 和 Opera 支持,Safari 和 IE/Edge 还不支持;而且,Chrome 也只支持 readText() 和 writeText()。

    参考链接:

    • clipboardjs.com/
    • www.w3.org/TR/clipboar…
    • developers.google.com/web/updates…
    • w3c.github.io/webappsec-s…

    起源地下载网 » Async Clipboard API来了

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元